1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_CreateBoxSFC, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 /* Logging support */ 18 PetscLogEvent DMPLEX_DistributionView, DMPLEX_DistributionLoad; 19 20 PetscBool Plexcite = PETSC_FALSE; 21 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 22 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 23 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 24 "journal = {SIAM Journal on Scientific Computing},\n" 25 "volume = {38},\n" 26 "number = {5},\n" 27 "pages = {S143--S155},\n" 28 "eprint = {http://arxiv.org/abs/1506.07749},\n" 29 "doi = {10.1137/15M1026092},\n" 30 "year = {2016},\n" 31 "petsc_uses={DMPlex},\n}\n"; 32 33 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 34 35 /*@ 36 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 37 38 Input Parameter: 39 . dm - The `DMPLEX` object 40 41 Output Parameter: 42 . simplex - Flag checking for a simplex 43 44 Level: intermediate 45 46 Note: 47 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 48 If the mesh has no cells, this returns `PETSC_FALSE`. 49 50 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 51 @*/ 52 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 53 { 54 DMPolytopeType ct; 55 PetscInt cStart, cEnd; 56 57 PetscFunctionBegin; 58 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 59 if (cEnd <= cStart) { 60 *simplex = PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 64 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 65 PetscFunctionReturn(PETSC_SUCCESS); 66 } 67 68 /*@ 69 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 70 71 Input Parameters: 72 + dm - The `DMPLEX` object 73 - height - The cell height in the Plex, 0 is the default 74 75 Output Parameters: 76 + cStart - The first "normal" cell, pass `NULL` if not needed 77 - cEnd - The upper bound on "normal" cells, pass `NULL` if not needed 78 79 Level: developer 80 81 Note: 82 This function requires that tensor cells are ordered last. 83 84 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 85 @*/ 86 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PeOp PetscInt *cStart, PeOp PetscInt *cEnd) 87 { 88 DMLabel ctLabel; 89 IS valueIS; 90 const PetscInt *ctypes; 91 PetscBool found = PETSC_FALSE; 92 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 93 94 PetscFunctionBegin; 95 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 96 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 97 PetscCall(ISGetLocalSize(valueIS, &Nct)); 98 PetscCall(ISGetIndices(valueIS, &ctypes)); 99 for (PetscInt t = 0; t < Nct; ++t) { 100 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 101 PetscInt ctS, ctE, ht; 102 103 if (ct == DM_POLYTOPE_UNKNOWN) { 104 // If any cells are not typed, just use all cells 105 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 106 break; 107 } 108 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 109 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 110 if (ctS >= ctE) continue; 111 // Check that a point has the right height 112 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 113 if (ht != height) continue; 114 cS = PetscMin(cS, ctS); 115 cE = PetscMax(cE, ctE); 116 found = PETSC_TRUE; 117 } 118 if (!Nct || !found) cS = cE = 0; 119 PetscCall(ISDestroy(&valueIS)); 120 // Reset label for fast lookup 121 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 122 if (cStart) *cStart = cS; 123 if (cEnd) *cEnd = cE; 124 PetscFunctionReturn(PETSC_SUCCESS); 125 } 126 127 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 128 { 129 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 130 PetscInt *sStart, *sEnd; 131 PetscViewerVTKFieldType *ft; 132 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 133 DMLabel depthLabel, ctLabel; 134 135 PetscFunctionBegin; 136 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 137 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 138 PetscCall(DMGetCoordinateDim(dm, &cdim)); 139 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 140 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 141 if (field >= 0) { 142 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 143 } else { 144 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 145 } 146 147 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 148 PetscCall(DMPlexGetDepth(dm, &depth)); 149 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 150 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 151 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 152 const DMPolytopeType ict = (DMPolytopeType)c; 153 PetscInt dep; 154 155 if (ict == DM_POLYTOPE_FV_GHOST) continue; 156 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 157 if (pStart >= 0) { 158 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 159 if (dep != depth - cellHeight) continue; 160 } 161 if (field >= 0) { 162 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 163 } else { 164 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 165 } 166 } 167 168 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 169 *types = 0; 170 171 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 172 if (globalvcdof[c]) ++(*types); 173 } 174 175 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 176 t = 0; 177 if (globalvcdof[DM_NUM_POLYTOPES]) { 178 sStart[t] = vStart; 179 sEnd[t] = vEnd; 180 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 181 ++t; 182 } 183 184 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 185 if (globalvcdof[c]) { 186 const DMPolytopeType ict = (DMPolytopeType)c; 187 188 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 189 sStart[t] = cStart; 190 sEnd[t] = cEnd; 191 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 192 ++t; 193 } 194 } 195 196 if (!*types) { 197 if (field >= 0) { 198 const char *fieldname; 199 200 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 201 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 202 } else { 203 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 204 } 205 } 206 207 *ssStart = sStart; 208 *ssEnd = sEnd; 209 *sft = ft; 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 214 { 215 PetscFunctionBegin; 216 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 217 PetscFunctionReturn(PETSC_SUCCESS); 218 } 219 220 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 221 { 222 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 223 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 224 225 PetscFunctionBegin; 226 *ft = PETSC_VTK_INVALID; 227 PetscCall(DMGetCoordinateDim(dm, &cdim)); 228 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 229 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 230 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 231 if (field >= 0) { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 234 } else { 235 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 236 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 237 } 238 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 239 if (globalvcdof[0]) { 240 *sStart = vStart; 241 *sEnd = vEnd; 242 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 243 else *ft = PETSC_VTK_POINT_FIELD; 244 } else if (globalvcdof[1]) { 245 *sStart = cStart; 246 *sEnd = cEnd; 247 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 248 else *ft = PETSC_VTK_CELL_FIELD; 249 } else { 250 if (field >= 0) { 251 const char *fieldname; 252 253 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 254 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 255 } else { 256 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 257 } 258 } 259 PetscFunctionReturn(PETSC_SUCCESS); 260 } 261 262 /*@ 263 DMPlexVecView1D - Plot many 1D solutions on the same line graph 264 265 Collective 266 267 Input Parameters: 268 + dm - The `DMPLEX` object 269 . n - The number of vectors 270 . u - The array of local vectors 271 - viewer - The `PetscViewer` 272 273 Level: advanced 274 275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 276 @*/ 277 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 278 { 279 DM cdm; 280 PetscDS ds; 281 PetscDraw draw = NULL; 282 PetscDrawLG lg; 283 Vec coordinates; 284 const PetscScalar *coords, **sol; 285 PetscReal *vals; 286 PetscInt *Nc; 287 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 288 char **names; 289 290 PetscFunctionBegin; 291 PetscCall(DMGetCoordinateDM(dm, &cdm)); 292 PetscCall(DMGetDS(dm, &ds)); 293 PetscCall(PetscDSGetNumFields(ds, &Nf)); 294 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 295 PetscCall(PetscDSGetComponents(ds, &Nc)); 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 298 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 299 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 300 301 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 302 for (PetscInt i = 0, l = 0; i < n; ++i) { 303 const char *vname; 304 305 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 306 for (PetscInt f = 0; f < Nf; ++f) { 307 PetscObject disc; 308 const char *fname; 309 char tmpname[PETSC_MAX_PATH_LEN]; 310 311 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 312 /* TODO Create names for components */ 313 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 314 PetscCall(PetscObjectGetName(disc, &fname)); 315 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 316 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 317 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 318 PetscCall(PetscStrallocpy(tmpname, &names[l])); 319 } 320 } 321 } 322 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 323 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 324 PetscCall(VecGetArrayRead(coordinates, &coords)); 325 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 326 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 327 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 328 PetscSection s; 329 PetscInt cdof, vdof; 330 331 PetscCall(DMGetLocalSection(dm, &s)); 332 PetscCall(PetscSectionGetDof(s, eStart, &cdof)); 333 PetscCall(PetscSectionGetDof(s, vStart, &vdof)); 334 if (cdof) { 335 if (vdof) { 336 // P_2 337 PetscInt vFirst = -1; 338 339 for (PetscInt e = eStart; e < eEnd; ++e) { 340 PetscScalar *xa, *xb, *svals; 341 const PetscInt *cone; 342 343 PetscCall(DMPlexGetCone(dm, e, &cone)); 344 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 345 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 346 if (e == eStart) vFirst = cone[0]; 347 for (PetscInt i = 0; i < n; ++i) { 348 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 349 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 350 } 351 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 352 if (e == eEnd - 1 && cone[1] != vFirst) { 353 for (PetscInt i = 0; i < n; ++i) { 354 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 355 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 356 } 357 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 358 for (PetscInt i = 0; i < n; ++i) { 359 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 360 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 361 } 362 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 363 } 364 } 365 } else { 366 // P_0 367 for (PetscInt e = eStart; e < eEnd; ++e) { 368 PetscScalar *xa, *xb, *svals; 369 const PetscInt *cone; 370 371 PetscCall(DMPlexGetCone(dm, e, &cone)); 372 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 373 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 374 for (PetscInt i = 0; i < n; ++i) { 375 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 376 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 377 } 378 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 379 } 380 } 381 } else if (vdof) { 382 // P_1 383 for (PetscInt v = vStart; v < vEnd; ++v) { 384 PetscScalar *x, *svals; 385 386 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 387 for (PetscInt i = 0; i < n; ++i) { 388 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 389 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 390 } 391 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 392 } 393 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Discretization not supported"); 394 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 395 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 396 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 397 PetscCall(PetscFree3(sol, names, vals)); 398 399 PetscCall(PetscDrawLGDraw(lg)); 400 PetscCall(PetscDrawLGDestroy(&lg)); 401 PetscFunctionReturn(PETSC_SUCCESS); 402 } 403 404 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 405 { 406 DM dm; 407 408 PetscFunctionBegin; 409 PetscCall(VecGetDM(u, &dm)); 410 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 411 PetscFunctionReturn(PETSC_SUCCESS); 412 } 413 414 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 415 { 416 DM dm; 417 PetscSection s; 418 PetscDraw draw, popup; 419 DM cdm; 420 PetscSection coordSection; 421 Vec coordinates; 422 const PetscScalar *array; 423 PetscReal lbound[3], ubound[3]; 424 PetscReal vbound[2], time; 425 PetscBool flg; 426 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 427 const char *name; 428 char title[PETSC_MAX_PATH_LEN]; 429 430 PetscFunctionBegin; 431 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 432 PetscCall(VecGetDM(v, &dm)); 433 PetscCall(DMGetCoordinateDim(dm, &dim)); 434 PetscCall(DMGetLocalSection(dm, &s)); 435 PetscCall(PetscSectionGetNumFields(s, &Nf)); 436 PetscCall(DMGetCoarsenLevel(dm, &level)); 437 PetscCall(DMGetCoordinateDM(dm, &cdm)); 438 PetscCall(DMGetLocalSection(cdm, &coordSection)); 439 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 440 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 441 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 442 443 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 444 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 445 446 PetscCall(VecGetLocalSize(coordinates, &N)); 447 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 448 PetscCall(PetscDrawClear(draw)); 449 450 /* Could implement something like DMDASelectFields() */ 451 for (f = 0; f < Nf; ++f) { 452 DM fdm = dm; 453 Vec fv = v; 454 IS fis; 455 char prefix[PETSC_MAX_PATH_LEN]; 456 const char *fname; 457 458 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 459 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 460 461 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 462 else prefix[0] = '\0'; 463 if (Nf > 1) { 464 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 465 PetscCall(VecGetSubVector(v, fis, &fv)); 466 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 467 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 468 } 469 for (comp = 0; comp < Nc; ++comp, ++w) { 470 PetscInt nmax = 2; 471 472 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 473 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 474 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 475 PetscCall(PetscDrawSetTitle(draw, title)); 476 477 /* TODO Get max and min only for this component */ 478 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 479 if (!flg) { 480 PetscCall(VecMin(fv, NULL, &vbound[0])); 481 PetscCall(VecMax(fv, NULL, &vbound[1])); 482 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 483 } 484 485 PetscCall(PetscDrawGetPopup(draw, &popup)); 486 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 487 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 488 PetscCall(VecGetArrayRead(fv, &array)); 489 for (c = cStart; c < cEnd; ++c) { 490 DMPolytopeType ct; 491 PetscScalar *coords = NULL, *a = NULL; 492 const PetscScalar *coords_arr; 493 PetscBool isDG; 494 PetscInt numCoords; 495 int color[4] = {-1, -1, -1, -1}; 496 497 PetscCall(DMPlexGetCellType(dm, c, &ct)); 498 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 499 if (a) { 500 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 501 color[1] = color[2] = color[3] = color[0]; 502 } else { 503 PetscScalar *vals = NULL; 504 PetscInt numVals, va; 505 506 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 507 if (!numVals) { 508 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 509 continue; 510 } 511 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 512 switch (numVals / Nc) { 513 case 1: /* P1 Clamped Segment Prism */ 514 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 515 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 516 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 517 break; 518 case 3: /* P1 Triangle */ 519 case 4: /* P1 Quadrangle */ 520 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 521 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 522 break; 523 case 6: /* P2 Triangle */ 524 case 8: /* P2 Quadrangle */ 525 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 526 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 527 break; 528 default: 529 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 530 } 531 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 532 } 533 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 534 switch (numCoords) { 535 case 6: 536 case 12: /* Localized triangle */ 537 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 538 break; 539 case 8: 540 case 16: /* Localized quadrilateral */ 541 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 543 } else { 544 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 545 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 546 } 547 break; 548 default: 549 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 550 } 551 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 552 } 553 PetscCall(VecRestoreArrayRead(fv, &array)); 554 PetscCall(PetscDrawFlush(draw)); 555 PetscCall(PetscDrawPause(draw)); 556 PetscCall(PetscDrawSave(draw)); 557 } 558 if (Nf > 1) { 559 PetscCall(VecRestoreSubVector(v, fis, &fv)); 560 PetscCall(ISDestroy(&fis)); 561 PetscCall(DMDestroy(&fdm)); 562 } 563 } 564 PetscFunctionReturn(PETSC_SUCCESS); 565 } 566 567 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 568 { 569 DM dm; 570 PetscDraw draw; 571 PetscInt dim; 572 PetscBool isnull; 573 574 PetscFunctionBegin; 575 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 576 PetscCall(PetscDrawIsNull(draw, &isnull)); 577 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 578 579 PetscCall(VecGetDM(v, &dm)); 580 PetscCall(DMGetCoordinateDim(dm, &dim)); 581 switch (dim) { 582 case 1: 583 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 584 break; 585 case 2: 586 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 587 break; 588 default: 589 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 590 } 591 PetscFunctionReturn(PETSC_SUCCESS); 592 } 593 594 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 595 { 596 DM dm; 597 Vec locv; 598 const char *name; 599 PetscSection section; 600 PetscInt pStart, pEnd; 601 PetscInt numFields; 602 PetscViewerVTKFieldType ft; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 607 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 608 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 609 PetscCall(VecCopy(v, locv)); 610 PetscCall(DMGetLocalSection(dm, §ion)); 611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 612 if (!numFields) { 613 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 614 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 615 } else { 616 PetscInt f; 617 618 for (f = 0; f < numFields; f++) { 619 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 620 if (ft == PETSC_VTK_INVALID) continue; 621 PetscCall(PetscObjectReference((PetscObject)locv)); 622 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 623 } 624 PetscCall(VecDestroy(&locv)); 625 } 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 641 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 642 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 643 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 644 PetscInt i, numFields; 645 PetscObject fe; 646 PetscBool fem = PETSC_FALSE; 647 Vec locv = v; 648 const char *name; 649 PetscInt step; 650 PetscReal time; 651 652 PetscCall(DMGetNumFields(dm, &numFields)); 653 for (i = 0; i < numFields; i++) { 654 PetscCall(DMGetField(dm, i, NULL, &fe)); 655 if (fe->classid == PETSCFE_CLASSID) { 656 fem = PETSC_TRUE; 657 break; 658 } 659 } 660 if (fem) { 661 PetscObject isZero; 662 663 PetscCall(DMGetLocalVector(dm, &locv)); 664 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 665 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 666 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 667 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 668 PetscCall(VecCopy(v, locv)); 669 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 670 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 671 } 672 if (isvtk) { 673 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 674 } else if (ishdf5) { 675 #if defined(PETSC_HAVE_HDF5) 676 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 677 #else 678 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 679 #endif 680 } else if (isdraw) { 681 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 682 } else if (ispython) { 683 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 684 } else if (isglvis) { 685 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 686 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 687 PetscCall(VecView_GLVis(locv, viewer)); 688 } else if (iscgns) { 689 #if defined(PETSC_HAVE_CGNS) 690 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 691 #else 692 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 693 #endif 694 } 695 if (fem) { 696 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 697 PetscCall(DMRestoreLocalVector(dm, &locv)); 698 } 699 } else { 700 PetscBool isseq; 701 702 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 703 if (isseq) PetscCall(VecView_Seq(v, viewer)); 704 else PetscCall(VecView_MPI(v, viewer)); 705 } 706 PetscFunctionReturn(PETSC_SUCCESS); 707 } 708 709 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 710 { 711 DM dm; 712 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 713 714 PetscFunctionBegin; 715 PetscCall(VecGetDM(v, &dm)); 716 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 723 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 724 if (isvtk || isdraw || isglvis || iscgns || ispython) { 725 Vec locv; 726 PetscObject isZero; 727 const char *name; 728 729 PetscCall(DMGetLocalVector(dm, &locv)); 730 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 731 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 732 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 733 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 734 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 735 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 736 PetscCall(VecView_Plex_Local(locv, viewer)); 737 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 738 PetscCall(DMRestoreLocalVector(dm, &locv)); 739 } else if (ishdf5) { 740 #if defined(PETSC_HAVE_HDF5) 741 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 742 #else 743 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 744 #endif 745 } else if (isexodusii) { 746 #if defined(PETSC_HAVE_EXODUSII) 747 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 748 #else 749 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 750 #endif 751 } else { 752 PetscBool isseq; 753 754 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 755 if (isseq) PetscCall(VecView_Seq(v, viewer)); 756 else PetscCall(VecView_MPI(v, viewer)); 757 } 758 PetscFunctionReturn(PETSC_SUCCESS); 759 } 760 761 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 762 { 763 DM dm; 764 MPI_Comm comm; 765 PetscViewerFormat format; 766 Vec v; 767 PetscBool isvtk, ishdf5; 768 769 PetscFunctionBegin; 770 PetscCall(VecGetDM(originalv, &dm)); 771 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 772 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 773 PetscCall(PetscViewerGetFormat(viewer, &format)); 774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 776 if (format == PETSC_VIEWER_NATIVE) { 777 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 778 /* this need a better fix */ 779 if (dm->useNatural) { 780 if (dm->sfNatural) { 781 const char *vecname; 782 PetscInt n, nroots; 783 784 PetscCall(VecGetLocalSize(originalv, &n)); 785 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 786 if (n == nroots) { 787 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 788 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 789 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 790 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 791 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 792 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 793 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 794 } else v = originalv; 795 } else v = originalv; 796 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 800 #else 801 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 802 #endif 803 } else if (isvtk) { 804 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 805 } else { 806 PetscBool isseq; 807 808 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 809 if (isseq) PetscCall(VecView_Seq(v, viewer)); 810 else PetscCall(VecView_MPI(v, viewer)); 811 } 812 if (v != originalv) PetscCall(VecDestroy(&v)); 813 PetscFunctionReturn(PETSC_SUCCESS); 814 } 815 816 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 817 { 818 DM dm; 819 PetscBool ishdf5; 820 821 PetscFunctionBegin; 822 PetscCall(VecGetDM(v, &dm)); 823 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 824 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 825 if (ishdf5) { 826 DM dmBC; 827 Vec gv; 828 const char *name; 829 830 PetscCall(DMGetOutputDM(dm, &dmBC)); 831 PetscCall(DMGetGlobalVector(dmBC, &gv)); 832 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 833 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 834 PetscCall(VecLoad_Default(gv, viewer)); 835 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 836 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 837 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 838 } else PetscCall(VecLoad_Default(v, viewer)); 839 PetscFunctionReturn(PETSC_SUCCESS); 840 } 841 842 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 843 { 844 DM dm; 845 PetscBool ishdf5, isexodusii, iscgns; 846 847 PetscFunctionBegin; 848 PetscCall(VecGetDM(v, &dm)); 849 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 850 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 851 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 852 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 853 if (ishdf5) { 854 #if defined(PETSC_HAVE_HDF5) 855 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 856 #else 857 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 858 #endif 859 } else if (isexodusii) { 860 #if defined(PETSC_HAVE_EXODUSII) 861 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 862 #else 863 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 864 #endif 865 } else if (iscgns) { 866 #if defined(PETSC_HAVE_CGNS) 867 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 868 #else 869 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 870 #endif 871 } else PetscCall(VecLoad_Default(v, viewer)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 876 { 877 DM dm; 878 PetscViewerFormat format; 879 PetscBool ishdf5; 880 881 PetscFunctionBegin; 882 PetscCall(VecGetDM(originalv, &dm)); 883 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 884 PetscCall(PetscViewerGetFormat(viewer, &format)); 885 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 886 if (format == PETSC_VIEWER_NATIVE) { 887 if (dm->useNatural) { 888 if (dm->sfNatural) { 889 if (ishdf5) { 890 #if defined(PETSC_HAVE_HDF5) 891 Vec v; 892 const char *vecname; 893 894 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 895 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 896 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 897 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 898 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 899 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 900 PetscCall(VecDestroy(&v)); 901 #else 902 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 903 #endif 904 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 905 } 906 } else PetscCall(VecLoad_Default(originalv, viewer)); 907 } 908 PetscFunctionReturn(PETSC_SUCCESS); 909 } 910 911 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 912 { 913 PetscSection coordSection; 914 Vec coordinates; 915 DMLabel depthLabel, celltypeLabel; 916 const char *name[4]; 917 const PetscScalar *a; 918 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 919 920 PetscFunctionBegin; 921 PetscCall(DMGetDimension(dm, &dim)); 922 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 923 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 924 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 925 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 926 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 927 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 928 PetscCall(VecGetArrayRead(coordinates, &a)); 929 name[0] = "vertex"; 930 name[1] = "edge"; 931 name[dim - 1] = "face"; 932 name[dim] = "cell"; 933 for (c = cStart; c < cEnd; ++c) { 934 PetscInt *closure = NULL; 935 PetscInt closureSize, cl, ct; 936 937 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 938 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 939 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 940 PetscCall(PetscViewerASCIIPushTab(viewer)); 941 for (cl = 0; cl < closureSize * 2; cl += 2) { 942 PetscInt point = closure[cl], depth, dof, off, d, p; 943 944 if ((point < pStart) || (point >= pEnd)) continue; 945 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 946 if (!dof) continue; 947 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 948 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 949 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 950 for (p = 0; p < dof / dim; ++p) { 951 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 952 for (d = 0; d < dim; ++d) { 953 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 955 } 956 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 957 } 958 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 959 } 960 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 961 PetscCall(PetscViewerASCIIPopTab(viewer)); 962 } 963 PetscCall(VecRestoreArrayRead(coordinates, &a)); 964 PetscFunctionReturn(PETSC_SUCCESS); 965 } 966 967 typedef enum { 968 CS_CARTESIAN, 969 CS_POLAR, 970 CS_CYLINDRICAL, 971 CS_SPHERICAL 972 } CoordSystem; 973 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 974 975 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 976 { 977 PetscInt i; 978 979 PetscFunctionBegin; 980 if (dim > 3) { 981 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 982 } else { 983 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 984 985 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 986 switch (cs) { 987 case CS_CARTESIAN: 988 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 989 break; 990 case CS_POLAR: 991 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 992 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 993 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 994 break; 995 case CS_CYLINDRICAL: 996 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 997 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 998 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 999 trcoords[2] = coords[2]; 1000 break; 1001 case CS_SPHERICAL: 1002 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 1003 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 1004 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 1005 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 1006 break; 1007 } 1008 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 1009 } 1010 PetscFunctionReturn(PETSC_SUCCESS); 1011 } 1012 1013 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 1014 { 1015 DM_Plex *mesh = (DM_Plex *)dm->data; 1016 DM cdm, cdmCell; 1017 PetscSection coordSection, coordSectionCell; 1018 Vec coordinates, coordinatesCell; 1019 PetscViewerFormat format; 1020 1021 PetscFunctionBegin; 1022 PetscCall(PetscViewerGetFormat(viewer, &format)); 1023 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1024 const char *name; 1025 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1026 PetscInt pStart, pEnd, p, numLabels, l; 1027 PetscMPIInt rank, size; 1028 1029 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1030 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1031 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1032 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1033 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1034 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1035 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1036 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1037 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1039 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1040 PetscCall(DMGetDimension(dm, &dim)); 1041 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1042 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1043 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1044 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1045 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1046 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1048 for (p = pStart; p < pEnd; ++p) { 1049 PetscInt dof, off, s; 1050 1051 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1052 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1053 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1054 } 1055 PetscCall(PetscViewerFlush(viewer)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1057 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1058 for (p = pStart; p < pEnd; ++p) { 1059 PetscInt dof, off, c; 1060 1061 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1062 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1063 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 1064 } 1065 PetscCall(PetscViewerFlush(viewer)); 1066 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1067 if (coordSection && coordinates) { 1068 CoordSystem cs = CS_CARTESIAN; 1069 const PetscScalar *array, *arrayCell = NULL; 1070 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1071 PetscMPIInt rank; 1072 const char *name; 1073 1074 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1075 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1076 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1077 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1078 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1079 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1080 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1081 pStart = PetscMin(pvStart, pcStart); 1082 pEnd = PetscMax(pvEnd, pcEnd); 1083 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1084 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1085 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1086 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1087 1088 PetscCall(VecGetArrayRead(coordinates, &array)); 1089 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1090 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1091 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1092 for (p = pStart; p < pEnd; ++p) { 1093 PetscInt dof, off; 1094 1095 if (p >= pvStart && p < pvEnd) { 1096 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1097 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1098 if (dof) { 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1100 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1102 } 1103 } 1104 if (cdmCell && p >= pcStart && p < pcEnd) { 1105 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1106 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1107 if (dof) { 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1109 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1110 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1111 } 1112 } 1113 } 1114 PetscCall(PetscViewerFlush(viewer)); 1115 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1116 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1117 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1118 } 1119 PetscCall(DMGetNumLabels(dm, &numLabels)); 1120 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1121 for (l = 0; l < numLabels; ++l) { 1122 DMLabel label; 1123 PetscBool isdepth; 1124 const char *name; 1125 1126 PetscCall(DMGetLabelName(dm, l, &name)); 1127 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1128 if (isdepth) continue; 1129 PetscCall(DMGetLabel(dm, name, &label)); 1130 PetscCall(DMLabelView(label, viewer)); 1131 } 1132 if (size > 1) { 1133 PetscSF sf; 1134 1135 PetscCall(DMGetPointSF(dm, &sf)); 1136 PetscCall(PetscSFView(sf, viewer)); 1137 } 1138 if (mesh->periodic.face_sfs) 1139 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1140 PetscCall(PetscViewerFlush(viewer)); 1141 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1142 const char *name, *color; 1143 const char *defcolors[3] = {"gray", "orange", "green"}; 1144 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1145 char lname[PETSC_MAX_PATH_LEN]; 1146 PetscReal scale = 2.0; 1147 PetscReal tikzscale = 1.0; 1148 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1149 double tcoords[3]; 1150 PetscScalar *coords; 1151 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1152 PetscMPIInt rank, size; 1153 char **names, **colors, **lcolors; 1154 PetscBool flg, lflg; 1155 PetscBT wp = NULL; 1156 PetscInt pEnd, pStart; 1157 1158 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1159 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1160 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1161 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1162 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1163 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1164 PetscCall(DMGetDimension(dm, &dim)); 1165 PetscCall(DMPlexGetDepth(dm, &depth)); 1166 PetscCall(DMGetNumLabels(dm, &numLabels)); 1167 numLabels = PetscMax(numLabels, 10); 1168 numColors = 10; 1169 numLColors = 10; 1170 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1171 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1172 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1173 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1174 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1175 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1176 n = 4; 1177 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1178 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1179 n = 4; 1180 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1181 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1182 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1183 if (!useLabels) numLabels = 0; 1184 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1185 if (!useColors) { 1186 numColors = 3; 1187 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1188 } 1189 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1190 if (!useColors) { 1191 numLColors = 4; 1192 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1193 } 1194 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1195 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1196 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1197 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1198 if (depth < dim) plotEdges = PETSC_FALSE; 1199 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1200 1201 /* filter points with labelvalue != labeldefaultvalue */ 1202 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1203 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1204 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1205 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1206 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1207 if (lflg) { 1208 DMLabel lbl; 1209 1210 PetscCall(DMGetLabel(dm, lname, &lbl)); 1211 if (lbl) { 1212 PetscInt val, defval; 1213 1214 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1215 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1216 for (c = pStart; c < pEnd; c++) { 1217 PetscInt *closure = NULL; 1218 PetscInt closureSize; 1219 1220 PetscCall(DMLabelGetValue(lbl, c, &val)); 1221 if (val == defval) continue; 1222 1223 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1225 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1226 } 1227 } 1228 } 1229 1230 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1231 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1232 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1234 \\documentclass[tikz]{standalone}\n\n\ 1235 \\usepackage{pgflibraryshapes}\n\ 1236 \\usetikzlibrary{backgrounds}\n\ 1237 \\usetikzlibrary{arrows}\n\ 1238 \\begin{document}\n")); 1239 if (size > 1) { 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1241 for (p = 0; p < size; ++p) { 1242 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1244 } 1245 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1246 } 1247 if (drawHasse) { 1248 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1249 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1265 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1266 } 1267 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1268 1269 /* Plot vertices */ 1270 PetscCall(VecGetArray(coordinates, &coords)); 1271 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1272 for (v = vStart; v < vEnd; ++v) { 1273 PetscInt off, dof, d; 1274 PetscBool isLabeled = PETSC_FALSE; 1275 1276 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1277 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1278 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1280 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1281 for (d = 0; d < dof; ++d) { 1282 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1283 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1284 } 1285 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1286 if (dim == 3) { 1287 PetscReal tmp = tcoords[1]; 1288 tcoords[1] = tcoords[2]; 1289 tcoords[2] = -tmp; 1290 } 1291 for (d = 0; d < dof; ++d) { 1292 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1293 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1294 } 1295 if (drawHasse) color = colors[0 % numColors]; 1296 else color = colors[rank % numColors]; 1297 for (l = 0; l < numLabels; ++l) { 1298 PetscInt val; 1299 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1300 if (val >= 0) { 1301 color = lcolors[l % numLColors]; 1302 isLabeled = PETSC_TRUE; 1303 break; 1304 } 1305 } 1306 if (drawNumbers[0]) { 1307 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1308 } else if (drawColors[0]) { 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1310 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1311 } 1312 PetscCall(VecRestoreArray(coordinates, &coords)); 1313 PetscCall(PetscViewerFlush(viewer)); 1314 /* Plot edges */ 1315 if (plotEdges) { 1316 PetscCall(VecGetArray(coordinates, &coords)); 1317 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1318 for (e = eStart; e < eEnd; ++e) { 1319 const PetscInt *cone; 1320 PetscInt coneSize, offA, offB, dof, d; 1321 1322 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1323 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1324 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1325 PetscCall(DMPlexGetCone(dm, e, &cone)); 1326 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1327 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1328 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1330 for (d = 0; d < dof; ++d) { 1331 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1332 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1333 } 1334 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1335 if (dim == 3) { 1336 PetscReal tmp = tcoords[1]; 1337 tcoords[1] = tcoords[2]; 1338 tcoords[2] = -tmp; 1339 } 1340 for (d = 0; d < dof; ++d) { 1341 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1342 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1343 } 1344 if (drawHasse) color = colors[1 % numColors]; 1345 else color = colors[rank % numColors]; 1346 for (l = 0; l < numLabels; ++l) { 1347 PetscInt val; 1348 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1349 if (val >= 0) { 1350 color = lcolors[l % numLColors]; 1351 break; 1352 } 1353 } 1354 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1355 } 1356 PetscCall(VecRestoreArray(coordinates, &coords)); 1357 PetscCall(PetscViewerFlush(viewer)); 1358 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1359 } 1360 /* Plot cells */ 1361 if (dim == 3 || !drawNumbers[1]) { 1362 for (e = eStart; e < eEnd; ++e) { 1363 const PetscInt *cone; 1364 1365 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1366 color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 break; 1373 } 1374 } 1375 PetscCall(DMPlexGetCone(dm, e, &cone)); 1376 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1377 } 1378 } else { 1379 DMPolytopeType ct; 1380 1381 /* Drawing a 2D polygon */ 1382 for (c = cStart; c < cEnd; ++c) { 1383 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1384 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1385 if (DMPolytopeTypeIsHybrid(ct)) { 1386 const PetscInt *cone; 1387 PetscInt coneSize, e; 1388 1389 PetscCall(DMPlexGetCone(dm, c, &cone)); 1390 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1391 for (e = 0; e < coneSize; ++e) { 1392 const PetscInt *econe; 1393 1394 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1395 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1396 } 1397 } else { 1398 PetscInt *closure = NULL; 1399 PetscInt closureSize, Nv = 0, v; 1400 1401 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1402 for (p = 0; p < closureSize * 2; p += 2) { 1403 const PetscInt point = closure[p]; 1404 1405 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1406 } 1407 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1408 for (v = 0; v <= Nv; ++v) { 1409 const PetscInt vertex = closure[v % Nv]; 1410 1411 if (v > 0) { 1412 if (plotEdges) { 1413 const PetscInt *edge; 1414 PetscInt endpoints[2], ne; 1415 1416 endpoints[0] = closure[v - 1]; 1417 endpoints[1] = vertex; 1418 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1419 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1420 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1421 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1422 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1423 } 1424 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1425 } 1426 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1427 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1428 } 1429 } 1430 } 1431 for (c = cStart; c < cEnd; ++c) { 1432 double ccoords[3] = {0.0, 0.0, 0.0}; 1433 PetscBool isLabeled = PETSC_FALSE; 1434 PetscScalar *cellCoords = NULL; 1435 const PetscScalar *array; 1436 PetscInt numCoords, cdim, d; 1437 PetscBool isDG; 1438 1439 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1440 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1441 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1442 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1443 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1444 for (p = 0; p < numCoords / cdim; ++p) { 1445 for (d = 0; d < cdim; ++d) { 1446 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1447 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1448 } 1449 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1450 if (cdim == 3) { 1451 PetscReal tmp = tcoords[1]; 1452 tcoords[1] = tcoords[2]; 1453 tcoords[2] = -tmp; 1454 } 1455 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1456 } 1457 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1458 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1459 for (d = 0; d < cdim; ++d) { 1460 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1461 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1462 } 1463 if (drawHasse) color = colors[depth % numColors]; 1464 else color = colors[rank % numColors]; 1465 for (l = 0; l < numLabels; ++l) { 1466 PetscInt val; 1467 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1468 if (val >= 0) { 1469 color = lcolors[l % numLColors]; 1470 isLabeled = PETSC_TRUE; 1471 break; 1472 } 1473 } 1474 if (drawNumbers[dim]) { 1475 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1476 } else if (drawColors[dim]) { 1477 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1478 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1479 } 1480 if (drawHasse) { 1481 int height = 0; 1482 1483 color = colors[depth % numColors]; 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1489 1490 if (depth > 2) { 1491 color = colors[1 % numColors]; 1492 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1493 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1494 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1495 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1496 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1497 } 1498 1499 color = colors[1 % numColors]; 1500 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1505 1506 color = colors[0 % numColors]; 1507 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1510 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1511 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1512 1513 for (p = pStart; p < pEnd; ++p) { 1514 const PetscInt *cone; 1515 PetscInt coneSize, cp; 1516 1517 PetscCall(DMPlexGetCone(dm, p, &cone)); 1518 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1519 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1520 } 1521 } 1522 PetscCall(PetscViewerFlush(viewer)); 1523 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1524 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1526 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1527 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1528 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1529 PetscCall(PetscFree3(names, colors, lcolors)); 1530 PetscCall(PetscBTDestroy(&wp)); 1531 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1532 Vec cown, acown; 1533 VecScatter sct; 1534 ISLocalToGlobalMapping g2l; 1535 IS gid, acis; 1536 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1537 MPI_Group ggroup, ngroup; 1538 PetscScalar *array, nid; 1539 const PetscInt *idxs; 1540 PetscInt *idxs2, *start, *adjacency, *work; 1541 PetscInt64 lm[3], gm[3]; 1542 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1543 PetscMPIInt d1, d2, rank; 1544 1545 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1546 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1547 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1548 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1549 #endif 1550 if (ncomm != MPI_COMM_NULL) { 1551 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1552 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1553 d1 = 0; 1554 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1555 nid = d2; 1556 PetscCallMPI(MPI_Group_free(&ggroup)); 1557 PetscCallMPI(MPI_Group_free(&ngroup)); 1558 PetscCallMPI(MPI_Comm_free(&ncomm)); 1559 } else nid = 0.0; 1560 1561 /* Get connectivity */ 1562 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1563 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1564 1565 /* filter overlapped local cells */ 1566 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1567 PetscCall(ISGetIndices(gid, &idxs)); 1568 PetscCall(ISGetLocalSize(gid, &cum)); 1569 PetscCall(PetscMalloc1(cum, &idxs2)); 1570 for (c = cStart, cum = 0; c < cEnd; c++) { 1571 if (idxs[c - cStart] < 0) continue; 1572 idxs2[cum++] = idxs[c - cStart]; 1573 } 1574 PetscCall(ISRestoreIndices(gid, &idxs)); 1575 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1576 PetscCall(ISDestroy(&gid)); 1577 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1578 1579 /* support for node-aware cell locality */ 1580 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1581 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1582 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1583 PetscCall(VecGetArray(cown, &array)); 1584 for (c = 0; c < numVertices; c++) array[c] = nid; 1585 PetscCall(VecRestoreArray(cown, &array)); 1586 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1587 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1588 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1589 PetscCall(ISDestroy(&acis)); 1590 PetscCall(VecScatterDestroy(&sct)); 1591 PetscCall(VecDestroy(&cown)); 1592 1593 /* compute edgeCut */ 1594 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1595 PetscCall(PetscMalloc1(cum, &work)); 1596 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1597 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1598 PetscCall(ISDestroy(&gid)); 1599 PetscCall(VecGetArray(acown, &array)); 1600 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1601 PetscInt totl; 1602 1603 totl = start[c + 1] - start[c]; 1604 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1605 for (i = 0; i < totl; i++) { 1606 if (work[i] < 0) { 1607 ect += 1; 1608 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1609 } 1610 } 1611 } 1612 PetscCall(PetscFree(work)); 1613 PetscCall(VecRestoreArray(acown, &array)); 1614 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1615 lm[1] = -numVertices; 1616 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1617 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1618 lm[0] = ect; /* edgeCut */ 1619 lm[1] = ectn; /* node-aware edgeCut */ 1620 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1621 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1622 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1623 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1624 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1625 #else 1626 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1627 #endif 1628 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1629 PetscCall(PetscFree(start)); 1630 PetscCall(PetscFree(adjacency)); 1631 PetscCall(VecDestroy(&acown)); 1632 } else { 1633 const char *name; 1634 PetscInt *sizes, *hybsizes, *ghostsizes; 1635 PetscInt locDepth, depth, cellHeight, dim, d; 1636 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1637 PetscInt numLabels, l, maxSize = 17; 1638 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1639 MPI_Comm comm; 1640 PetscMPIInt size, rank; 1641 1642 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1643 PetscCallMPI(MPI_Comm_size(comm, &size)); 1644 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1645 PetscCall(DMGetDimension(dm, &dim)); 1646 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1647 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1648 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1649 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1650 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1651 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1652 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1653 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1654 gcNum = gcEnd - gcStart; 1655 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1656 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1657 for (d = 0; d <= depth; d++) { 1658 PetscInt Nc[2] = {0, 0}, ict; 1659 1660 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1661 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1662 ict = ct0; 1663 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1664 ct0 = (DMPolytopeType)ict; 1665 for (p = pStart; p < pEnd; ++p) { 1666 DMPolytopeType ct; 1667 1668 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1669 if (ct == ct0) ++Nc[0]; 1670 else ++Nc[1]; 1671 } 1672 if (size < maxSize) { 1673 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1674 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1675 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1676 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1677 for (p = 0; p < size; ++p) { 1678 if (rank == 0) { 1679 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1680 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1681 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1682 } 1683 } 1684 } else { 1685 PetscInt locMinMax[2]; 1686 1687 locMinMax[0] = Nc[0] + Nc[1]; 1688 locMinMax[1] = Nc[0] + Nc[1]; 1689 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1690 locMinMax[0] = Nc[1]; 1691 locMinMax[1] = Nc[1]; 1692 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1693 if (d == depth) { 1694 locMinMax[0] = gcNum; 1695 locMinMax[1] = gcNum; 1696 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1697 } 1698 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1699 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1700 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1701 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1702 } 1703 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1704 } 1705 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1706 { 1707 const PetscReal *maxCell; 1708 const PetscReal *L; 1709 PetscBool localized; 1710 1711 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1712 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1713 if (L || localized) { 1714 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1715 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1716 if (L) { 1717 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1718 for (d = 0; d < dim; ++d) { 1719 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1720 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1721 } 1722 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1723 } 1724 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1725 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1726 } 1727 } 1728 PetscCall(DMGetNumLabels(dm, &numLabels)); 1729 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1730 for (l = 0; l < numLabels; ++l) { 1731 DMLabel label; 1732 const char *name; 1733 PetscInt *values; 1734 PetscInt numValues, v; 1735 1736 PetscCall(DMGetLabelName(dm, l, &name)); 1737 PetscCall(DMGetLabel(dm, name, &label)); 1738 PetscCall(DMLabelGetNumValues(label, &numValues)); 1739 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1740 1741 { // Extract array of DMLabel values so it can be sorted 1742 IS is_values; 1743 const PetscInt *is_values_local = NULL; 1744 1745 PetscCall(DMLabelGetValueIS(label, &is_values)); 1746 PetscCall(ISGetIndices(is_values, &is_values_local)); 1747 PetscCall(PetscMalloc1(numValues, &values)); 1748 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1749 PetscCall(PetscSortInt(numValues, values)); 1750 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1751 PetscCall(ISDestroy(&is_values)); 1752 } 1753 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1754 for (v = 0; v < numValues; ++v) { 1755 PetscInt size; 1756 1757 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1758 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1759 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1760 } 1761 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1762 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1763 PetscCall(PetscFree(values)); 1764 } 1765 { 1766 char **labelNames; 1767 PetscInt Nl = numLabels; 1768 PetscBool flg; 1769 1770 PetscCall(PetscMalloc1(Nl, &labelNames)); 1771 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1772 for (l = 0; l < Nl; ++l) { 1773 DMLabel label; 1774 1775 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1776 if (flg) { 1777 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1778 PetscCall(DMLabelView(label, viewer)); 1779 } 1780 PetscCall(PetscFree(labelNames[l])); 1781 } 1782 PetscCall(PetscFree(labelNames)); 1783 } 1784 /* If no fields are specified, people do not want to see adjacency */ 1785 if (dm->Nf) { 1786 PetscInt f; 1787 1788 for (f = 0; f < dm->Nf; ++f) { 1789 const char *name; 1790 1791 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1792 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1793 PetscCall(PetscViewerASCIIPushTab(viewer)); 1794 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1795 if (dm->fields[f].adjacency[0]) { 1796 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1797 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1798 } else { 1799 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1800 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1801 } 1802 PetscCall(PetscViewerASCIIPopTab(viewer)); 1803 } 1804 } 1805 DMPlexTransform tr; 1806 1807 PetscCall(DMPlexGetTransform(dm, &tr)); 1808 if (tr) { 1809 PetscCall(PetscViewerASCIIPushTab(viewer)); 1810 PetscCall(PetscViewerASCIIPrintf(viewer, "Created using transform:\n")); 1811 PetscCall(DMPlexTransformView(tr, viewer)); 1812 PetscCall(PetscViewerASCIIPopTab(viewer)); 1813 } 1814 PetscCall(DMGetCoarseDM(dm, &cdm)); 1815 if (cdm) { 1816 PetscCall(PetscViewerASCIIPushTab(viewer)); 1817 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1818 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1819 PetscCall(PetscViewerASCIIPopTab(viewer)); 1820 } 1821 } 1822 PetscFunctionReturn(PETSC_SUCCESS); 1823 } 1824 1825 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt lC, PetscInt cC, PetscInt cell, const PetscScalar coords[]) 1826 { 1827 DMPolytopeType ct; 1828 PetscMPIInt rank; 1829 PetscInt cdim; 1830 int lineColor, cellColor; 1831 1832 PetscFunctionBegin; 1833 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1834 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1835 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1836 lineColor = (int)(lC < 0 ? PETSC_DRAW_BLACK : lC); 1837 cellColor = (int)(cC < 0 ? PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2 : cC); 1838 switch (ct) { 1839 case DM_POLYTOPE_SEGMENT: 1840 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1841 switch (cdim) { 1842 case 1: { 1843 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1844 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1845 1846 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, lineColor)); 1847 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, lineColor)); 1848 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, lineColor)); 1849 } break; 1850 case 2: { 1851 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1852 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1853 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1854 1855 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1856 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, lineColor)); 1857 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, lineColor)); 1858 } break; 1859 default: 1860 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1861 } 1862 break; 1863 case DM_POLYTOPE_TRIANGLE: 1864 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1865 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1866 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1867 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1868 break; 1869 case DM_POLYTOPE_QUADRILATERAL: 1870 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1871 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), cellColor, cellColor, cellColor)); 1872 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1873 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1874 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1875 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1876 break; 1877 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1878 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1879 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), cellColor, cellColor, cellColor)); 1880 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), lineColor)); 1881 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), lineColor)); 1882 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), lineColor)); 1883 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), lineColor)); 1884 break; 1885 case DM_POLYTOPE_FV_GHOST: 1886 break; 1887 default: 1888 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1889 } 1890 PetscFunctionReturn(PETSC_SUCCESS); 1891 } 1892 1893 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1894 { 1895 PetscReal centroid[2] = {0., 0.}; 1896 PetscMPIInt rank; 1897 PetscMPIInt fillColor; 1898 1899 PetscFunctionBegin; 1900 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1901 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1902 for (PetscInt v = 0; v < Nv; ++v) { 1903 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1904 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1905 } 1906 for (PetscInt e = 0; e < Nv; ++e) { 1907 refCoords[0] = refVertices[e * 2 + 0]; 1908 refCoords[1] = refVertices[e * 2 + 1]; 1909 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1910 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1911 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1912 } 1913 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1914 for (PetscInt d = 0; d < edgeDiv; ++d) { 1915 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1916 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1917 } 1918 } 1919 PetscFunctionReturn(PETSC_SUCCESS); 1920 } 1921 1922 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1923 { 1924 DMPolytopeType ct; 1925 1926 PetscFunctionBegin; 1927 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1928 switch (ct) { 1929 case DM_POLYTOPE_TRIANGLE: { 1930 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1931 1932 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1933 } break; 1934 case DM_POLYTOPE_QUADRILATERAL: { 1935 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1936 1937 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1938 } break; 1939 default: 1940 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1941 } 1942 PetscFunctionReturn(PETSC_SUCCESS); 1943 } 1944 1945 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1946 { 1947 PetscDraw draw; 1948 DM cdm; 1949 PetscSection coordSection; 1950 Vec coordinates; 1951 PetscReal xyl[3], xyr[3]; 1952 PetscReal *refCoords, *edgeCoords; 1953 PetscBool isnull, drawAffine; 1954 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv, lineColor = PETSC_DETERMINE, cellColor = PETSC_DETERMINE; 1955 1956 PetscFunctionBegin; 1957 PetscCall(DMGetCoordinateDim(dm, &dim)); 1958 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1959 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1960 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1961 edgeDiv = cDegree + 1; 1962 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_line_color", &lineColor, NULL)); 1963 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_cell_color", &cellColor, NULL)); 1964 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1965 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1966 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1967 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1968 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1969 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1970 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1971 1972 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1973 PetscCall(PetscDrawIsNull(draw, &isnull)); 1974 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1975 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1976 1977 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1978 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1979 PetscCall(PetscDrawClear(draw)); 1980 1981 for (c = cStart; c < cEnd; ++c) { 1982 PetscScalar *coords = NULL; 1983 const PetscScalar *coords_arr; 1984 PetscInt numCoords; 1985 PetscBool isDG; 1986 1987 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1988 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, lineColor, cellColor, c, coords)); 1989 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1990 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1991 } 1992 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1993 PetscCall(PetscDrawFlush(draw)); 1994 PetscCall(PetscDrawPause(draw)); 1995 PetscCall(PetscDrawSave(draw)); 1996 PetscFunctionReturn(PETSC_SUCCESS); 1997 } 1998 1999 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 2000 { 2001 DM odm = dm, rdm = dm, cdm; 2002 PetscFE fe; 2003 PetscSpace sp; 2004 PetscClassId id; 2005 PetscInt degree; 2006 PetscBool hoView = PETSC_TRUE; 2007 2008 PetscFunctionBegin; 2009 PetscObjectOptionsBegin((PetscObject)dm); 2010 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 2011 PetscOptionsEnd(); 2012 PetscCall(PetscObjectReference((PetscObject)dm)); 2013 *hdm = dm; 2014 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 2015 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2016 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 2017 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 2018 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 2019 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 2020 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 2021 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 2022 DM cdm, rcdm; 2023 Mat In; 2024 Vec cl, rcl; 2025 2026 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 2027 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 2028 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 2029 PetscCall(DMGetCoordinateDM(odm, &cdm)); 2030 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 2031 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 2032 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 2033 PetscCall(DMSetCoarseDM(rcdm, cdm)); 2034 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2035 PetscCall(MatMult(In, cl, rcl)); 2036 PetscCall(MatDestroy(&In)); 2037 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2038 PetscCall(DMDestroy(&odm)); 2039 odm = rdm; 2040 } 2041 *hdm = rdm; 2042 PetscFunctionReturn(PETSC_SUCCESS); 2043 } 2044 2045 #if defined(PETSC_HAVE_EXODUSII) 2046 #include <exodusII.h> 2047 #include <petscviewerexodusii.h> 2048 #endif 2049 2050 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2051 { 2052 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2053 char name[PETSC_MAX_PATH_LEN]; 2054 2055 PetscFunctionBegin; 2056 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2057 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2059 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2060 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2061 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2063 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2064 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2065 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2066 if (iascii) { 2067 PetscViewerFormat format; 2068 PetscCall(PetscViewerGetFormat(viewer, &format)); 2069 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2070 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2071 } else if (ishdf5) { 2072 #if defined(PETSC_HAVE_HDF5) 2073 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2074 #else 2075 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2076 #endif 2077 } else if (isvtk) { 2078 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2079 } else if (isdraw) { 2080 DM hdm; 2081 2082 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2083 PetscCall(DMPlexView_Draw(hdm, viewer)); 2084 PetscCall(DMDestroy(&hdm)); 2085 } else if (isglvis) { 2086 PetscCall(DMPlexView_GLVis(dm, viewer)); 2087 #if defined(PETSC_HAVE_EXODUSII) 2088 } else if (isexodus) { 2089 /* 2090 exodusII requires that all sets be part of exactly one cell set. 2091 If the dm does not have a "Cell Sets" label defined, we create one 2092 with ID 1, containing all cells. 2093 Note that if the Cell Sets label is defined but does not cover all cells, 2094 we may still have a problem. This should probably be checked here or in the viewer; 2095 */ 2096 PetscInt numCS; 2097 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2098 if (!numCS) { 2099 PetscInt cStart, cEnd, c; 2100 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2101 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2102 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2103 } 2104 PetscCall(DMView_PlexExodusII(dm, viewer)); 2105 #endif 2106 #if defined(PETSC_HAVE_CGNS) 2107 } else if (iscgns) { 2108 PetscCall(DMView_PlexCGNS(dm, viewer)); 2109 #endif 2110 } else if (ispython) { 2111 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2112 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2113 /* Optionally view the partition */ 2114 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2115 if (flg) { 2116 Vec ranks; 2117 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2118 PetscCall(VecView(ranks, viewer)); 2119 PetscCall(VecDestroy(&ranks)); 2120 } 2121 /* Optionally view a label */ 2122 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2123 if (flg) { 2124 DMLabel label; 2125 Vec val; 2126 2127 PetscCall(DMGetLabel(dm, name, &label)); 2128 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2129 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2130 PetscCall(VecView(val, viewer)); 2131 PetscCall(VecDestroy(&val)); 2132 } 2133 PetscFunctionReturn(PETSC_SUCCESS); 2134 } 2135 2136 /*@ 2137 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2138 2139 Collective 2140 2141 Input Parameters: 2142 + dm - The `DM` whose topology is to be saved 2143 - viewer - The `PetscViewer` to save it in 2144 2145 Level: advanced 2146 2147 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2148 @*/ 2149 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2150 { 2151 PetscBool ishdf5; 2152 2153 PetscFunctionBegin; 2154 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2155 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2156 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2157 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2158 if (ishdf5) { 2159 #if defined(PETSC_HAVE_HDF5) 2160 PetscViewerFormat format; 2161 PetscCall(PetscViewerGetFormat(viewer, &format)); 2162 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2163 IS globalPointNumbering; 2164 2165 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2166 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2167 PetscCall(ISDestroy(&globalPointNumbering)); 2168 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2169 #else 2170 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2171 #endif 2172 } 2173 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2174 PetscFunctionReturn(PETSC_SUCCESS); 2175 } 2176 2177 /*@ 2178 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2179 2180 Collective 2181 2182 Input Parameters: 2183 + dm - The `DM` whose coordinates are to be saved 2184 - viewer - The `PetscViewer` for saving 2185 2186 Level: advanced 2187 2188 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2189 @*/ 2190 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2191 { 2192 PetscBool ishdf5; 2193 2194 PetscFunctionBegin; 2195 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2196 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2197 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2198 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2199 if (ishdf5) { 2200 #if defined(PETSC_HAVE_HDF5) 2201 PetscViewerFormat format; 2202 PetscCall(PetscViewerGetFormat(viewer, &format)); 2203 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2204 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2205 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2206 #else 2207 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2208 #endif 2209 } 2210 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2211 PetscFunctionReturn(PETSC_SUCCESS); 2212 } 2213 2214 /*@ 2215 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2216 2217 Collective 2218 2219 Input Parameters: 2220 + dm - The `DM` whose labels are to be saved 2221 - viewer - The `PetscViewer` for saving 2222 2223 Level: advanced 2224 2225 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2226 @*/ 2227 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2228 { 2229 PetscBool ishdf5; 2230 2231 PetscFunctionBegin; 2232 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2233 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2234 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2235 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2236 if (ishdf5) { 2237 #if defined(PETSC_HAVE_HDF5) 2238 IS globalPointNumbering; 2239 PetscViewerFormat format; 2240 2241 PetscCall(PetscViewerGetFormat(viewer, &format)); 2242 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2243 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2244 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2245 PetscCall(ISDestroy(&globalPointNumbering)); 2246 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2247 #else 2248 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2249 #endif 2250 } 2251 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2252 PetscFunctionReturn(PETSC_SUCCESS); 2253 } 2254 2255 /*@ 2256 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2257 2258 Collective 2259 2260 Input Parameters: 2261 + dm - The `DM` that contains the topology on which the section to be saved is defined 2262 . viewer - The `PetscViewer` for saving 2263 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2264 2265 Level: advanced 2266 2267 Notes: 2268 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (`dm`) points. When the topology (`dm`) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 2269 2270 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2271 2272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2273 @*/ 2274 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2275 { 2276 PetscBool ishdf5; 2277 2278 PetscFunctionBegin; 2279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2280 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2281 if (!sectiondm) sectiondm = dm; 2282 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2283 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2284 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2285 if (ishdf5) { 2286 #if defined(PETSC_HAVE_HDF5) 2287 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2288 #else 2289 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2290 #endif 2291 } 2292 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2293 PetscFunctionReturn(PETSC_SUCCESS); 2294 } 2295 2296 /*@ 2297 DMPlexGlobalVectorView - Saves a global vector 2298 2299 Collective 2300 2301 Input Parameters: 2302 + dm - The `DM` that represents the topology 2303 . viewer - The `PetscViewer` to save data with 2304 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2305 - vec - The global vector to be saved 2306 2307 Level: advanced 2308 2309 Notes: 2310 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2311 2312 Calling sequence: 2313 .vb 2314 DMCreate(PETSC_COMM_WORLD, &dm); 2315 DMSetType(dm, DMPLEX); 2316 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2317 DMClone(dm, §iondm); 2318 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2319 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2320 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2321 PetscSectionSetChart(section, pStart, pEnd); 2322 PetscSectionSetUp(section); 2323 DMSetLocalSection(sectiondm, section); 2324 PetscSectionDestroy(§ion); 2325 DMGetGlobalVector(sectiondm, &vec); 2326 PetscObjectSetName((PetscObject)vec, "vec_name"); 2327 DMPlexTopologyView(dm, viewer); 2328 DMPlexSectionView(dm, viewer, sectiondm); 2329 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2330 DMRestoreGlobalVector(sectiondm, &vec); 2331 DMDestroy(§iondm); 2332 DMDestroy(&dm); 2333 .ve 2334 2335 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2336 @*/ 2337 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2338 { 2339 PetscBool ishdf5; 2340 2341 PetscFunctionBegin; 2342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2343 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2344 if (!sectiondm) sectiondm = dm; 2345 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2346 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2347 /* Check consistency */ 2348 { 2349 PetscSection section; 2350 PetscBool includesConstraints; 2351 PetscInt m, m1; 2352 2353 PetscCall(VecGetLocalSize(vec, &m1)); 2354 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2355 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2356 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2357 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2358 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2359 } 2360 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2361 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2362 if (ishdf5) { 2363 #if defined(PETSC_HAVE_HDF5) 2364 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2365 #else 2366 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2367 #endif 2368 } 2369 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2370 PetscFunctionReturn(PETSC_SUCCESS); 2371 } 2372 2373 /*@ 2374 DMPlexLocalVectorView - Saves a local vector 2375 2376 Collective 2377 2378 Input Parameters: 2379 + dm - The `DM` that represents the topology 2380 . viewer - The `PetscViewer` to save data with 2381 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2382 - vec - The local vector to be saved 2383 2384 Level: advanced 2385 2386 Note: 2387 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2388 2389 Calling sequence: 2390 .vb 2391 DMCreate(PETSC_COMM_WORLD, &dm); 2392 DMSetType(dm, DMPLEX); 2393 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2394 DMClone(dm, §iondm); 2395 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2396 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2397 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2398 PetscSectionSetChart(section, pStart, pEnd); 2399 PetscSectionSetUp(section); 2400 DMSetLocalSection(sectiondm, section); 2401 DMGetLocalVector(sectiondm, &vec); 2402 PetscObjectSetName((PetscObject)vec, "vec_name"); 2403 DMPlexTopologyView(dm, viewer); 2404 DMPlexSectionView(dm, viewer, sectiondm); 2405 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2406 DMRestoreLocalVector(sectiondm, &vec); 2407 DMDestroy(§iondm); 2408 DMDestroy(&dm); 2409 .ve 2410 2411 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2412 @*/ 2413 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2414 { 2415 PetscBool ishdf5; 2416 2417 PetscFunctionBegin; 2418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2419 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2420 if (!sectiondm) sectiondm = dm; 2421 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2422 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2423 /* Check consistency */ 2424 { 2425 PetscSection section; 2426 PetscBool includesConstraints; 2427 PetscInt m, m1; 2428 2429 PetscCall(VecGetLocalSize(vec, &m1)); 2430 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2431 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2432 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2433 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2434 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2435 } 2436 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2437 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2438 if (ishdf5) { 2439 #if defined(PETSC_HAVE_HDF5) 2440 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2441 #else 2442 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2443 #endif 2444 } 2445 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2446 PetscFunctionReturn(PETSC_SUCCESS); 2447 } 2448 2449 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2450 { 2451 PetscBool ishdf5; 2452 2453 PetscFunctionBegin; 2454 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2455 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2456 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2457 if (ishdf5) { 2458 #if defined(PETSC_HAVE_HDF5) 2459 PetscViewerFormat format; 2460 PetscCall(PetscViewerGetFormat(viewer, &format)); 2461 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2462 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2463 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2464 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2465 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2466 PetscFunctionReturn(PETSC_SUCCESS); 2467 #else 2468 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2469 #endif 2470 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2471 } 2472 2473 /*@ 2474 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2475 2476 Collective 2477 2478 Input Parameters: 2479 + dm - The `DM` into which the topology is loaded 2480 - viewer - The `PetscViewer` for the saved topology 2481 2482 Output Parameter: 2483 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; 2484 `NULL` if unneeded 2485 2486 Level: advanced 2487 2488 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2489 `PetscViewer`, `PetscSF` 2490 @*/ 2491 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2492 { 2493 PetscBool ishdf5; 2494 2495 PetscFunctionBegin; 2496 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2497 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2498 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2499 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2500 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2501 if (ishdf5) { 2502 #if defined(PETSC_HAVE_HDF5) 2503 PetscViewerFormat format; 2504 PetscCall(PetscViewerGetFormat(viewer, &format)); 2505 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2506 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2507 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2508 #else 2509 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2510 #endif 2511 } 2512 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2513 PetscFunctionReturn(PETSC_SUCCESS); 2514 } 2515 2516 /*@ 2517 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2518 2519 Collective 2520 2521 Input Parameters: 2522 + dm - The `DM` into which the coordinates are loaded 2523 . viewer - The `PetscViewer` for the saved coordinates 2524 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2525 2526 Level: advanced 2527 2528 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2529 `PetscSF`, `PetscViewer` 2530 @*/ 2531 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2532 { 2533 PetscBool ishdf5; 2534 2535 PetscFunctionBegin; 2536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2537 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2538 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2539 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2540 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2541 if (ishdf5) { 2542 #if defined(PETSC_HAVE_HDF5) 2543 PetscViewerFormat format; 2544 PetscCall(PetscViewerGetFormat(viewer, &format)); 2545 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2546 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2547 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2548 #else 2549 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2550 #endif 2551 } 2552 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2553 PetscFunctionReturn(PETSC_SUCCESS); 2554 } 2555 2556 /*@ 2557 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2558 2559 Collective 2560 2561 Input Parameters: 2562 + dm - The `DM` into which the labels are loaded 2563 . viewer - The `PetscViewer` for the saved labels 2564 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2565 2566 Level: advanced 2567 2568 Note: 2569 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2570 2571 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2572 `PetscSF`, `PetscViewer` 2573 @*/ 2574 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2575 { 2576 PetscBool ishdf5; 2577 2578 PetscFunctionBegin; 2579 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2580 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2581 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2582 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2583 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2584 if (ishdf5) { 2585 #if defined(PETSC_HAVE_HDF5) 2586 PetscViewerFormat format; 2587 2588 PetscCall(PetscViewerGetFormat(viewer, &format)); 2589 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2590 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2591 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2592 #else 2593 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2594 #endif 2595 } 2596 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2597 PetscFunctionReturn(PETSC_SUCCESS); 2598 } 2599 2600 /*@ 2601 DMPlexSectionLoad - Loads section into a `DMPLEX` 2602 2603 Collective 2604 2605 Input Parameters: 2606 + dm - The `DM` that represents the topology 2607 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2608 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2609 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2610 2611 Output Parameters: 2612 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2613 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2614 2615 Level: advanced 2616 2617 Notes: 2618 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2619 2620 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2621 2622 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2623 2624 Example using 2 processes: 2625 .vb 2626 NX (number of points on dm): 4 2627 sectionA : the on-disk section 2628 vecA : a vector associated with sectionA 2629 sectionB : sectiondm's local section constructed in this function 2630 vecB (local) : a vector associated with sectiondm's local section 2631 vecB (global) : a vector associated with sectiondm's global section 2632 2633 rank 0 rank 1 2634 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2635 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2636 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2637 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2638 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2639 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2640 sectionB->atlasDof : 1 0 1 | 1 3 2641 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2642 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2643 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2644 .ve 2645 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2646 2647 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2648 @*/ 2649 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, PeOp DM sectiondm, PetscSF globalToLocalPointSF, PeOp PetscSF *globalDofSF, PeOp PetscSF *localDofSF) 2650 { 2651 PetscBool ishdf5; 2652 2653 PetscFunctionBegin; 2654 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2655 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2656 if (!sectiondm) sectiondm = dm; 2657 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2658 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2659 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2660 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2661 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2662 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2663 if (ishdf5) { 2664 #if defined(PETSC_HAVE_HDF5) 2665 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2666 #else 2667 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2668 #endif 2669 } 2670 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2671 PetscFunctionReturn(PETSC_SUCCESS); 2672 } 2673 2674 /*@ 2675 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2676 2677 Collective 2678 2679 Input Parameters: 2680 + dm - The `DM` that represents the topology 2681 . viewer - The `PetscViewer` that represents the on-disk vector data 2682 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2683 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2684 - vec - The global vector to set values of 2685 2686 Level: advanced 2687 2688 Notes: 2689 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2690 2691 Calling sequence: 2692 .vb 2693 DMCreate(PETSC_COMM_WORLD, &dm); 2694 DMSetType(dm, DMPLEX); 2695 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2696 DMPlexTopologyLoad(dm, viewer, &sfX); 2697 DMClone(dm, §iondm); 2698 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2699 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2700 DMGetGlobalVector(sectiondm, &vec); 2701 PetscObjectSetName((PetscObject)vec, "vec_name"); 2702 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2703 DMRestoreGlobalVector(sectiondm, &vec); 2704 PetscSFDestroy(&gsf); 2705 PetscSFDestroy(&sfX); 2706 DMDestroy(§iondm); 2707 DMDestroy(&dm); 2708 .ve 2709 2710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2711 `PetscSF`, `PetscViewer` 2712 @*/ 2713 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2714 { 2715 PetscBool ishdf5; 2716 2717 PetscFunctionBegin; 2718 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2719 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2720 if (!sectiondm) sectiondm = dm; 2721 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2722 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2723 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2724 /* Check consistency */ 2725 { 2726 PetscSection section; 2727 PetscBool includesConstraints; 2728 PetscInt m, m1; 2729 2730 PetscCall(VecGetLocalSize(vec, &m1)); 2731 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2732 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2733 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2734 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2735 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2736 } 2737 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2738 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2739 if (ishdf5) { 2740 #if defined(PETSC_HAVE_HDF5) 2741 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2742 #else 2743 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2744 #endif 2745 } 2746 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2747 PetscFunctionReturn(PETSC_SUCCESS); 2748 } 2749 2750 /*@ 2751 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2752 2753 Collective 2754 2755 Input Parameters: 2756 + dm - The `DM` that represents the topology 2757 . viewer - The `PetscViewer` that represents the on-disk vector data 2758 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2759 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2760 - vec - The local vector to set values of 2761 2762 Level: advanced 2763 2764 Notes: 2765 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2766 2767 Calling sequence: 2768 .vb 2769 DMCreate(PETSC_COMM_WORLD, &dm); 2770 DMSetType(dm, DMPLEX); 2771 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2772 DMPlexTopologyLoad(dm, viewer, &sfX); 2773 DMClone(dm, §iondm); 2774 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2775 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2776 DMGetLocalVector(sectiondm, &vec); 2777 PetscObjectSetName((PetscObject)vec, "vec_name"); 2778 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2779 DMRestoreLocalVector(sectiondm, &vec); 2780 PetscSFDestroy(&lsf); 2781 PetscSFDestroy(&sfX); 2782 DMDestroy(§iondm); 2783 DMDestroy(&dm); 2784 .ve 2785 2786 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2787 `PetscSF`, `PetscViewer` 2788 @*/ 2789 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2790 { 2791 PetscBool ishdf5; 2792 2793 PetscFunctionBegin; 2794 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2795 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2796 if (!sectiondm) sectiondm = dm; 2797 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2798 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2799 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2800 /* Check consistency */ 2801 { 2802 PetscSection section; 2803 PetscBool includesConstraints; 2804 PetscInt m, m1; 2805 2806 PetscCall(VecGetLocalSize(vec, &m1)); 2807 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2808 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2809 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2810 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2811 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2812 } 2813 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2814 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2815 if (ishdf5) { 2816 #if defined(PETSC_HAVE_HDF5) 2817 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2818 #else 2819 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2820 #endif 2821 } 2822 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2823 PetscFunctionReturn(PETSC_SUCCESS); 2824 } 2825 2826 PetscErrorCode DMDestroy_Plex(DM dm) 2827 { 2828 DM_Plex *mesh = (DM_Plex *)dm->data; 2829 2830 PetscFunctionBegin; 2831 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2832 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2833 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2834 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", NULL)); 2835 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2836 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2837 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2838 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2839 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2840 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2841 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2842 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2843 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2844 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2845 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2846 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2847 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2848 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2849 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2850 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2851 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2852 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2853 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2854 PetscCall(PetscFree(mesh->cones)); 2855 PetscCall(PetscFree(mesh->coneOrientations)); 2856 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2857 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2858 PetscCall(PetscFree(mesh->supports)); 2859 PetscCall(PetscFree(mesh->cellTypes)); 2860 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2861 PetscCall(PetscFree(mesh->tetgenOpts)); 2862 PetscCall(PetscFree(mesh->triangleOpts)); 2863 PetscCall(PetscFree(mesh->transformType)); 2864 PetscCall(PetscFree(mesh->distributionName)); 2865 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2866 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2867 PetscCall(ISDestroy(&mesh->subpointIS)); 2868 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2869 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2870 if (mesh->periodic.face_sfs) { 2871 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2872 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2873 } 2874 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2875 if (mesh->periodic.periodic_points) { 2876 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2877 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2878 } 2879 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2880 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2881 PetscCall(ISDestroy(&mesh->anchorIS)); 2882 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2883 PetscCall(PetscFree(mesh->parents)); 2884 PetscCall(PetscFree(mesh->childIDs)); 2885 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2886 PetscCall(PetscFree(mesh->children)); 2887 PetscCall(DMDestroy(&mesh->referenceTree)); 2888 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2889 PetscCall(PetscFree(mesh->neighbors)); 2890 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2891 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2892 PetscCall(DMPlexTransformDestroy(&mesh->transform)); 2893 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2894 PetscCall(PetscFree(mesh)); 2895 PetscFunctionReturn(PETSC_SUCCESS); 2896 } 2897 2898 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2899 { 2900 PetscSection sectionGlobal, sectionLocal; 2901 PetscInt bs = -1, mbs; 2902 PetscInt localSize, localStart = 0; 2903 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2904 MatType mtype; 2905 ISLocalToGlobalMapping ltog; 2906 2907 PetscFunctionBegin; 2908 PetscCall(MatInitializePackage()); 2909 mtype = dm->mattype; 2910 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2911 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2912 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2913 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2914 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2915 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2916 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2917 PetscCall(MatSetType(*J, mtype)); 2918 PetscCall(MatSetFromOptions(*J)); 2919 PetscCall(MatGetBlockSize(*J, &mbs)); 2920 if (mbs > 1) bs = mbs; 2921 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2922 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2923 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2924 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2925 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2926 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2927 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2928 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2929 if (!isShell) { 2930 // There are three states with pblocks, since block starts can have no dofs: 2931 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2932 // TRUE) Block Start: The first entry in a block has been added 2933 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2934 PetscBT blst; 2935 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2936 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2937 const PetscInt *perm = NULL; 2938 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2939 PetscInt pStart, pEnd, dof, cdof, num_fields; 2940 2941 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2942 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2943 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2944 2945 PetscCall(PetscCalloc1(localSize, &pblocks)); 2946 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2947 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2948 // We need to process in the permuted order to get block sizes right 2949 for (PetscInt point = pStart; point < pEnd; ++point) { 2950 const PetscInt p = perm ? perm[point] : point; 2951 2952 switch (dm->blocking_type) { 2953 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2954 PetscInt bdof, offset; 2955 2956 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2957 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2958 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2959 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2960 if (dof > 0) { 2961 // State change 2962 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2963 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2964 2965 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2966 // Signal block concatenation 2967 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2968 } 2969 dof = dof < 0 ? -(dof + 1) : dof; 2970 bdof = cdof && (dof - cdof) ? 1 : dof; 2971 if (dof) { 2972 if (bs < 0) { 2973 bs = bdof; 2974 } else if (bs != bdof) { 2975 bs = 1; 2976 } 2977 } 2978 } break; 2979 case DM_BLOCKING_FIELD_NODE: { 2980 for (PetscInt field = 0; field < num_fields; field++) { 2981 PetscInt num_comp, bdof, offset; 2982 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2983 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2984 if (dof < 0) continue; 2985 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2986 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2987 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2988 PetscInt num_nodes = dof / num_comp; 2989 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2990 // Handle possibly constant block size (unlikely) 2991 bdof = cdof && (dof - cdof) ? 1 : dof; 2992 if (dof) { 2993 if (bs < 0) { 2994 bs = bdof; 2995 } else if (bs != bdof) { 2996 bs = 1; 2997 } 2998 } 2999 } 3000 } break; 3001 } 3002 } 3003 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 3004 /* Must have same blocksize on all procs (some might have no points) */ 3005 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 3006 bsLocal[1] = bs; 3007 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 3008 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 3009 else bs = bsMinMax[0]; 3010 bs = PetscMax(1, bs); 3011 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 3012 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 3013 PetscCall(MatSetBlockSize(*J, bs)); 3014 PetscCall(MatSetUp(*J)); 3015 } else { 3016 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 3017 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 3018 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 3019 } 3020 if (pblocks) { // Consolidate blocks 3021 PetscInt nblocks = 0; 3022 pblocks[0] = PetscAbs(pblocks[0]); 3023 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 3024 if (pblocks[i] == 0) continue; 3025 // Negative block size indicates the blocks should be concatenated 3026 if (pblocks[i] < 0) { 3027 pblocks[i] = -pblocks[i]; 3028 pblocks[nblocks - 1] += pblocks[i]; 3029 } else { 3030 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 3031 } 3032 for (PetscInt j = 1; j < pblocks[i]; j++) 3033 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 3034 } 3035 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 3036 } 3037 PetscCall(PetscFree(pblocks)); 3038 } 3039 PetscCall(MatSetDM(*J, dm)); 3040 PetscFunctionReturn(PETSC_SUCCESS); 3041 } 3042 3043 /*@ 3044 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3045 3046 Not Collective 3047 3048 Input Parameter: 3049 . dm - The `DMPLEX` 3050 3051 Output Parameter: 3052 . subsection - The subdomain section 3053 3054 Level: developer 3055 3056 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3057 @*/ 3058 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3059 { 3060 DM_Plex *mesh = (DM_Plex *)dm->data; 3061 3062 PetscFunctionBegin; 3063 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3064 if (!mesh->subdomainSection) { 3065 PetscSection section; 3066 PetscSF sf; 3067 3068 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3069 PetscCall(DMGetLocalSection(dm, §ion)); 3070 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3071 PetscCall(PetscSFDestroy(&sf)); 3072 } 3073 *subsection = mesh->subdomainSection; 3074 PetscFunctionReturn(PETSC_SUCCESS); 3075 } 3076 3077 /*@ 3078 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3079 3080 Not Collective 3081 3082 Input Parameter: 3083 . dm - The `DMPLEX` 3084 3085 Output Parameters: 3086 + pStart - The first mesh point 3087 - pEnd - The upper bound for mesh points 3088 3089 Level: beginner 3090 3091 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3092 @*/ 3093 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3094 { 3095 DM_Plex *mesh = (DM_Plex *)dm->data; 3096 3097 PetscFunctionBegin; 3098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3099 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3100 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3101 PetscFunctionReturn(PETSC_SUCCESS); 3102 } 3103 3104 /*@ 3105 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3106 3107 Not Collective 3108 3109 Input Parameters: 3110 + dm - The `DMPLEX` 3111 . pStart - The first mesh point 3112 - pEnd - The upper bound for mesh points 3113 3114 Level: beginner 3115 3116 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3117 @*/ 3118 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3119 { 3120 DM_Plex *mesh = (DM_Plex *)dm->data; 3121 3122 PetscFunctionBegin; 3123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3124 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3125 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3126 PetscCall(PetscFree(mesh->cellTypes)); 3127 PetscFunctionReturn(PETSC_SUCCESS); 3128 } 3129 3130 /*@ 3131 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3132 3133 Not Collective 3134 3135 Input Parameters: 3136 + dm - The `DMPLEX` 3137 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3138 3139 Output Parameter: 3140 . size - The cone size for point `p` 3141 3142 Level: beginner 3143 3144 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3145 @*/ 3146 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3147 { 3148 DM_Plex *mesh = (DM_Plex *)dm->data; 3149 3150 PetscFunctionBegin; 3151 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3152 PetscAssertPointer(size, 3); 3153 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3154 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3155 PetscFunctionReturn(PETSC_SUCCESS); 3156 } 3157 3158 /*@ 3159 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3160 3161 Not Collective 3162 3163 Input Parameters: 3164 + dm - The `DMPLEX` 3165 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3166 - size - The cone size for point `p` 3167 3168 Level: beginner 3169 3170 Note: 3171 This should be called after `DMPlexSetChart()`. 3172 3173 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3174 @*/ 3175 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3176 { 3177 DM_Plex *mesh = (DM_Plex *)dm->data; 3178 3179 PetscFunctionBegin; 3180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3181 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3182 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3183 PetscFunctionReturn(PETSC_SUCCESS); 3184 } 3185 3186 /*@C 3187 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3188 3189 Not Collective 3190 3191 Input Parameters: 3192 + dm - The `DMPLEX` 3193 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3194 3195 Output Parameter: 3196 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3197 3198 Level: beginner 3199 3200 Fortran Notes: 3201 `cone` must be declared with 3202 .vb 3203 PetscInt, pointer :: cone(:) 3204 .ve 3205 3206 You must call `DMPlexRestoreCone()` after you finish using the array. 3207 `DMPlexRestoreCone()` is not needed/available in C. 3208 3209 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3210 @*/ 3211 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3212 { 3213 DM_Plex *mesh = (DM_Plex *)dm->data; 3214 PetscInt off; 3215 3216 PetscFunctionBegin; 3217 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3218 PetscAssertPointer(cone, 3); 3219 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3220 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3221 PetscFunctionReturn(PETSC_SUCCESS); 3222 } 3223 3224 /*@ 3225 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3226 3227 Not Collective 3228 3229 Input Parameters: 3230 + dm - The `DMPLEX` 3231 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3232 3233 Output Parameters: 3234 + pConesSection - `PetscSection` describing the layout of `pCones` 3235 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3236 3237 Level: intermediate 3238 3239 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3240 @*/ 3241 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PeOp PetscSection *pConesSection, PeOp IS *pCones) 3242 { 3243 PetscSection cs, newcs; 3244 PetscInt *cones; 3245 PetscInt *newarr = NULL; 3246 PetscInt n; 3247 3248 PetscFunctionBegin; 3249 PetscCall(DMPlexGetCones(dm, &cones)); 3250 PetscCall(DMPlexGetConeSection(dm, &cs)); 3251 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3252 if (pConesSection) *pConesSection = newcs; 3253 if (pCones) { 3254 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3255 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3256 } 3257 PetscFunctionReturn(PETSC_SUCCESS); 3258 } 3259 3260 /*@ 3261 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3262 3263 Not Collective 3264 3265 Input Parameters: 3266 + dm - The `DMPLEX` 3267 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3268 3269 Output Parameter: 3270 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3271 3272 Level: advanced 3273 3274 Notes: 3275 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3276 3277 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3278 3279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3280 `DMPlexGetDepth()`, `IS` 3281 @*/ 3282 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3283 { 3284 IS *expandedPointsAll; 3285 PetscInt depth; 3286 3287 PetscFunctionBegin; 3288 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3289 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3290 PetscAssertPointer(expandedPoints, 3); 3291 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3292 *expandedPoints = expandedPointsAll[0]; 3293 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3294 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3295 PetscFunctionReturn(PETSC_SUCCESS); 3296 } 3297 3298 /*@ 3299 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3300 (DAG points of depth 0, i.e., without cones). 3301 3302 Not Collective 3303 3304 Input Parameters: 3305 + dm - The `DMPLEX` 3306 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3307 3308 Output Parameters: 3309 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3310 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3311 - sections - (optional) An array of sections which describe mappings from points to their cone points 3312 3313 Level: advanced 3314 3315 Notes: 3316 Like `DMPlexGetConeTuple()` but recursive. 3317 3318 Array `expandedPoints` has size equal to `depth`. Each `expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 3319 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3320 3321 Array section has size equal to `depth`. Each `PetscSection` `sections`[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows\: 3322 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3323 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3324 3325 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3326 `DMPlexGetDepth()`, `PetscSection`, `IS` 3327 @*/ 3328 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3329 { 3330 const PetscInt *arr0 = NULL, *cone = NULL; 3331 PetscInt *arr = NULL, *newarr = NULL; 3332 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3333 IS *expandedPoints_; 3334 PetscSection *sections_; 3335 3336 PetscFunctionBegin; 3337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3338 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3339 if (depth) PetscAssertPointer(depth, 3); 3340 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3341 if (sections) PetscAssertPointer(sections, 5); 3342 PetscCall(ISGetLocalSize(points, &n)); 3343 PetscCall(ISGetIndices(points, &arr0)); 3344 PetscCall(DMPlexGetDepth(dm, &depth_)); 3345 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3346 PetscCall(PetscCalloc1(depth_, §ions_)); 3347 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3348 for (d = depth_ - 1; d >= 0; d--) { 3349 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3350 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3351 for (i = 0; i < n; i++) { 3352 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3353 if (arr[i] >= start && arr[i] < end) { 3354 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3355 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3356 } else { 3357 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3358 } 3359 } 3360 PetscCall(PetscSectionSetUp(sections_[d])); 3361 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3362 PetscCall(PetscMalloc1(newn, &newarr)); 3363 for (i = 0; i < n; i++) { 3364 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3365 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3366 if (cn > 1) { 3367 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3368 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3369 } else { 3370 newarr[co] = arr[i]; 3371 } 3372 } 3373 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3374 arr = newarr; 3375 n = newn; 3376 } 3377 PetscCall(ISRestoreIndices(points, &arr0)); 3378 *depth = depth_; 3379 if (expandedPoints) *expandedPoints = expandedPoints_; 3380 else { 3381 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3382 PetscCall(PetscFree(expandedPoints_)); 3383 } 3384 if (sections) *sections = sections_; 3385 else { 3386 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3387 PetscCall(PetscFree(sections_)); 3388 } 3389 PetscFunctionReturn(PETSC_SUCCESS); 3390 } 3391 3392 /*@ 3393 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3394 3395 Not Collective 3396 3397 Input Parameters: 3398 + dm - The `DMPLEX` 3399 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3400 3401 Output Parameters: 3402 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3403 . expandedPoints - (optional) An array of recursively expanded cones 3404 - sections - (optional) An array of sections which describe mappings from points to their cone points 3405 3406 Level: advanced 3407 3408 Note: 3409 See `DMPlexGetConeRecursive()` 3410 3411 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3412 `DMPlexGetDepth()`, `IS`, `PetscSection` 3413 @*/ 3414 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PeOp PetscInt *depth, PeOp IS *expandedPoints[], PeOp PetscSection *sections[]) 3415 { 3416 PetscInt d, depth_; 3417 3418 PetscFunctionBegin; 3419 PetscCall(DMPlexGetDepth(dm, &depth_)); 3420 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3421 if (depth) *depth = 0; 3422 if (expandedPoints) { 3423 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3424 PetscCall(PetscFree(*expandedPoints)); 3425 } 3426 if (sections) { 3427 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3428 PetscCall(PetscFree(*sections)); 3429 } 3430 PetscFunctionReturn(PETSC_SUCCESS); 3431 } 3432 3433 /*@ 3434 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 3435 3436 Not Collective 3437 3438 Input Parameters: 3439 + dm - The `DMPLEX` 3440 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3441 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3442 3443 Level: beginner 3444 3445 Note: 3446 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3447 3448 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3449 @*/ 3450 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3451 { 3452 DM_Plex *mesh = (DM_Plex *)dm->data; 3453 PetscInt dof, off, c; 3454 3455 PetscFunctionBegin; 3456 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3457 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3458 if (dof) PetscAssertPointer(cone, 3); 3459 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3460 if (PetscDefined(USE_DEBUG)) { 3461 PetscInt pStart, pEnd; 3462 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3463 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3464 for (c = 0; c < dof; ++c) { 3465 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3466 mesh->cones[off + c] = cone[c]; 3467 } 3468 } else { 3469 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3470 } 3471 PetscFunctionReturn(PETSC_SUCCESS); 3472 } 3473 3474 /*@C 3475 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3476 3477 Not Collective 3478 3479 Input Parameters: 3480 + dm - The `DMPLEX` 3481 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3482 3483 Output Parameter: 3484 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3485 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3486 3487 Level: beginner 3488 3489 Note: 3490 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3491 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3492 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3493 with the identity. 3494 3495 Fortran Notes: 3496 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3497 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3498 3499 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3500 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3501 @*/ 3502 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3503 { 3504 DM_Plex *mesh = (DM_Plex *)dm->data; 3505 PetscInt off; 3506 3507 PetscFunctionBegin; 3508 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3509 if (PetscDefined(USE_DEBUG)) { 3510 PetscInt dof; 3511 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3512 if (dof) PetscAssertPointer(coneOrientation, 3); 3513 } 3514 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3515 3516 *coneOrientation = &mesh->coneOrientations[off]; 3517 PetscFunctionReturn(PETSC_SUCCESS); 3518 } 3519 3520 /*@ 3521 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3522 3523 Not Collective 3524 3525 Input Parameters: 3526 + dm - The `DMPLEX` 3527 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3528 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3529 3530 Level: beginner 3531 3532 Notes: 3533 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3534 3535 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3536 3537 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3538 @*/ 3539 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3540 { 3541 DM_Plex *mesh = (DM_Plex *)dm->data; 3542 PetscInt pStart, pEnd; 3543 PetscInt dof, off, c; 3544 3545 PetscFunctionBegin; 3546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3547 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3548 if (dof) PetscAssertPointer(coneOrientation, 3); 3549 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3550 if (PetscDefined(USE_DEBUG)) { 3551 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3552 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3553 for (c = 0; c < dof; ++c) { 3554 PetscInt cdof, o = coneOrientation[c]; 3555 3556 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3557 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3558 mesh->coneOrientations[off + c] = o; 3559 } 3560 } else { 3561 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3562 } 3563 PetscFunctionReturn(PETSC_SUCCESS); 3564 } 3565 3566 /*@ 3567 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3568 3569 Not Collective 3570 3571 Input Parameters: 3572 + dm - The `DMPLEX` 3573 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3574 . conePos - The local index in the cone where the point should be put 3575 - conePoint - The mesh point to insert 3576 3577 Level: beginner 3578 3579 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3580 @*/ 3581 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3582 { 3583 DM_Plex *mesh = (DM_Plex *)dm->data; 3584 PetscInt pStart, pEnd; 3585 PetscInt dof, off; 3586 3587 PetscFunctionBegin; 3588 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3589 if (PetscDefined(USE_DEBUG)) { 3590 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3591 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3592 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3593 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3594 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3595 } 3596 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3597 mesh->cones[off + conePos] = conePoint; 3598 PetscFunctionReturn(PETSC_SUCCESS); 3599 } 3600 3601 /*@ 3602 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3603 3604 Not Collective 3605 3606 Input Parameters: 3607 + dm - The `DMPLEX` 3608 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3609 . conePos - The local index in the cone where the point should be put 3610 - coneOrientation - The point orientation to insert 3611 3612 Level: beginner 3613 3614 Note: 3615 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3616 3617 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3618 @*/ 3619 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3620 { 3621 DM_Plex *mesh = (DM_Plex *)dm->data; 3622 PetscInt pStart, pEnd; 3623 PetscInt dof, off; 3624 3625 PetscFunctionBegin; 3626 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3627 if (PetscDefined(USE_DEBUG)) { 3628 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3629 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3630 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3631 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3632 } 3633 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3634 mesh->coneOrientations[off + conePos] = coneOrientation; 3635 PetscFunctionReturn(PETSC_SUCCESS); 3636 } 3637 3638 /*@C 3639 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3640 3641 Not collective 3642 3643 Input Parameters: 3644 + dm - The DMPlex 3645 - p - The point, which must lie in the chart set with DMPlexSetChart() 3646 3647 Output Parameters: 3648 + cone - An array of points which are on the in-edges for point `p` 3649 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3650 integer giving the prescription for cone traversal. 3651 3652 Level: beginner 3653 3654 Notes: 3655 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3656 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3657 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3658 with the identity. 3659 3660 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3661 3662 Fortran Notes: 3663 `cone` and `ornt` must be declared with 3664 .vb 3665 PetscInt, pointer :: cone(:) 3666 PetscInt, pointer :: ornt(:) 3667 .ve 3668 3669 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3670 @*/ 3671 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, PeOp const PetscInt *cone[], PeOp const PetscInt *ornt[]) 3672 { 3673 DM_Plex *mesh = (DM_Plex *)dm->data; 3674 3675 PetscFunctionBegin; 3676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3677 if (mesh->tr) { 3678 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3679 } else { 3680 PetscInt off; 3681 if (PetscDefined(USE_DEBUG)) { 3682 PetscInt dof; 3683 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3684 if (dof) { 3685 if (cone) PetscAssertPointer(cone, 3); 3686 if (ornt) PetscAssertPointer(ornt, 4); 3687 } 3688 } 3689 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3690 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3691 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3692 } 3693 PetscFunctionReturn(PETSC_SUCCESS); 3694 } 3695 3696 /*@C 3697 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3698 3699 Not Collective 3700 3701 Input Parameters: 3702 + dm - The DMPlex 3703 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3704 . cone - An array of points which are on the in-edges for point p 3705 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3706 integer giving the prescription for cone traversal. 3707 3708 Level: beginner 3709 3710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3711 @*/ 3712 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3713 { 3714 DM_Plex *mesh = (DM_Plex *)dm->data; 3715 3716 PetscFunctionBegin; 3717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3718 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3719 PetscFunctionReturn(PETSC_SUCCESS); 3720 } 3721 3722 /*@ 3723 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3724 3725 Not Collective 3726 3727 Input Parameters: 3728 + dm - The `DMPLEX` 3729 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3730 3731 Output Parameter: 3732 . size - The support size for point `p` 3733 3734 Level: beginner 3735 3736 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3737 @*/ 3738 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3739 { 3740 DM_Plex *mesh = (DM_Plex *)dm->data; 3741 3742 PetscFunctionBegin; 3743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3744 PetscAssertPointer(size, 3); 3745 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3746 PetscFunctionReturn(PETSC_SUCCESS); 3747 } 3748 3749 /*@ 3750 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3751 3752 Not Collective 3753 3754 Input Parameters: 3755 + dm - The `DMPLEX` 3756 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3757 - size - The support size for point `p` 3758 3759 Level: beginner 3760 3761 Note: 3762 This should be called after `DMPlexSetChart()`. 3763 3764 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3765 @*/ 3766 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3767 { 3768 DM_Plex *mesh = (DM_Plex *)dm->data; 3769 3770 PetscFunctionBegin; 3771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3772 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3773 PetscFunctionReturn(PETSC_SUCCESS); 3774 } 3775 3776 /*@C 3777 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3778 3779 Not Collective 3780 3781 Input Parameters: 3782 + dm - The `DMPLEX` 3783 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3784 3785 Output Parameter: 3786 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3787 3788 Level: beginner 3789 3790 Fortran Notes: 3791 `support` must be declared with 3792 .vb 3793 PetscInt, pointer :: support(:) 3794 .ve 3795 3796 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3797 `DMPlexRestoreSupport()` is not needed/available in C. 3798 3799 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3800 @*/ 3801 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3802 { 3803 DM_Plex *mesh = (DM_Plex *)dm->data; 3804 PetscInt off; 3805 3806 PetscFunctionBegin; 3807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3808 PetscAssertPointer(support, 3); 3809 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3810 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3811 PetscFunctionReturn(PETSC_SUCCESS); 3812 } 3813 3814 /*@ 3815 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3816 3817 Not Collective 3818 3819 Input Parameters: 3820 + dm - The `DMPLEX` 3821 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3822 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3823 3824 Level: beginner 3825 3826 Note: 3827 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3828 3829 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3830 @*/ 3831 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3832 { 3833 DM_Plex *mesh = (DM_Plex *)dm->data; 3834 PetscInt pStart, pEnd; 3835 PetscInt dof, off, c; 3836 3837 PetscFunctionBegin; 3838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3839 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3840 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3841 if (dof) PetscAssertPointer(support, 3); 3842 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3843 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3844 for (c = 0; c < dof; ++c) { 3845 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3846 mesh->supports[off + c] = support[c]; 3847 } 3848 PetscFunctionReturn(PETSC_SUCCESS); 3849 } 3850 3851 /*@ 3852 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3853 3854 Not Collective 3855 3856 Input Parameters: 3857 + dm - The `DMPLEX` 3858 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3859 . supportPos - The local index in the cone where the point should be put 3860 - supportPoint - The mesh point to insert 3861 3862 Level: beginner 3863 3864 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3865 @*/ 3866 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3867 { 3868 DM_Plex *mesh = (DM_Plex *)dm->data; 3869 PetscInt pStart, pEnd; 3870 PetscInt dof, off; 3871 3872 PetscFunctionBegin; 3873 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3874 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3875 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3876 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3877 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3878 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3879 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3880 mesh->supports[off + supportPos] = supportPoint; 3881 PetscFunctionReturn(PETSC_SUCCESS); 3882 } 3883 3884 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3885 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3886 { 3887 switch (ct) { 3888 case DM_POLYTOPE_SEGMENT: 3889 if (o == -1) return -2; 3890 break; 3891 case DM_POLYTOPE_TRIANGLE: 3892 if (o == -3) return -1; 3893 if (o == -2) return -3; 3894 if (o == -1) return -2; 3895 break; 3896 case DM_POLYTOPE_QUADRILATERAL: 3897 if (o == -4) return -2; 3898 if (o == -3) return -1; 3899 if (o == -2) return -4; 3900 if (o == -1) return -3; 3901 break; 3902 default: 3903 return o; 3904 } 3905 return o; 3906 } 3907 3908 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3909 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3910 { 3911 switch (ct) { 3912 case DM_POLYTOPE_SEGMENT: 3913 if ((o == -2) || (o == 1)) return -1; 3914 if (o == -1) return 0; 3915 break; 3916 case DM_POLYTOPE_TRIANGLE: 3917 if (o == -3) return -2; 3918 if (o == -2) return -1; 3919 if (o == -1) return -3; 3920 break; 3921 case DM_POLYTOPE_QUADRILATERAL: 3922 if (o == -4) return -2; 3923 if (o == -3) return -1; 3924 if (o == -2) return -4; 3925 if (o == -1) return -3; 3926 break; 3927 default: 3928 return o; 3929 } 3930 return o; 3931 } 3932 3933 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3934 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3935 { 3936 PetscInt pStart, pEnd, p; 3937 3938 PetscFunctionBegin; 3939 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3940 for (p = pStart; p < pEnd; ++p) { 3941 const PetscInt *cone, *ornt; 3942 PetscInt coneSize, c; 3943 3944 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3945 PetscCall(DMPlexGetCone(dm, p, &cone)); 3946 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3947 for (c = 0; c < coneSize; ++c) { 3948 DMPolytopeType ct; 3949 const PetscInt o = ornt[c]; 3950 3951 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3952 switch (ct) { 3953 case DM_POLYTOPE_SEGMENT: 3954 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3955 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3956 break; 3957 case DM_POLYTOPE_TRIANGLE: 3958 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3959 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3960 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3961 break; 3962 case DM_POLYTOPE_QUADRILATERAL: 3963 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3964 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3965 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3966 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3967 break; 3968 default: 3969 break; 3970 } 3971 } 3972 } 3973 PetscFunctionReturn(PETSC_SUCCESS); 3974 } 3975 3976 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3977 { 3978 DM_Plex *mesh = (DM_Plex *)dm->data; 3979 3980 PetscFunctionBeginHot; 3981 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3982 if (useCone) { 3983 PetscCall(DMPlexGetConeSize(dm, p, size)); 3984 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3985 } else { 3986 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3987 PetscCall(DMPlexGetSupport(dm, p, arr)); 3988 } 3989 } else { 3990 if (useCone) { 3991 const PetscSection s = mesh->coneSection; 3992 const PetscInt ps = p - s->pStart; 3993 const PetscInt off = s->atlasOff[ps]; 3994 3995 *size = s->atlasDof[ps]; 3996 *arr = mesh->cones + off; 3997 *ornt = mesh->coneOrientations + off; 3998 } else { 3999 const PetscSection s = mesh->supportSection; 4000 const PetscInt ps = p - s->pStart; 4001 const PetscInt off = s->atlasOff[ps]; 4002 4003 *size = s->atlasDof[ps]; 4004 *arr = mesh->supports + off; 4005 } 4006 } 4007 PetscFunctionReturn(PETSC_SUCCESS); 4008 } 4009 4010 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 4011 { 4012 DM_Plex *mesh = (DM_Plex *)dm->data; 4013 4014 PetscFunctionBeginHot; 4015 if (PetscDefined(USE_DEBUG) || mesh->tr) { 4016 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 4017 } 4018 PetscFunctionReturn(PETSC_SUCCESS); 4019 } 4020 4021 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4022 { 4023 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4024 PetscInt *closure; 4025 const PetscInt *tmp = NULL, *tmpO = NULL; 4026 PetscInt off = 0, tmpSize, t; 4027 4028 PetscFunctionBeginHot; 4029 if (ornt) { 4030 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4031 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4032 } 4033 if (*points) { 4034 closure = *points; 4035 } else { 4036 PetscInt maxConeSize, maxSupportSize; 4037 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4038 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4039 } 4040 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4041 if (ct == DM_POLYTOPE_UNKNOWN) { 4042 closure[off++] = p; 4043 closure[off++] = 0; 4044 for (t = 0; t < tmpSize; ++t) { 4045 closure[off++] = tmp[t]; 4046 closure[off++] = tmpO ? tmpO[t] : 0; 4047 } 4048 } else { 4049 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4050 4051 /* We assume that cells with a valid type have faces with a valid type */ 4052 closure[off++] = p; 4053 closure[off++] = ornt; 4054 for (t = 0; t < tmpSize; ++t) { 4055 DMPolytopeType ft; 4056 4057 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4058 closure[off++] = tmp[arr[t]]; 4059 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4060 } 4061 } 4062 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4063 if (numPoints) *numPoints = tmpSize + 1; 4064 if (points) *points = closure; 4065 PetscFunctionReturn(PETSC_SUCCESS); 4066 } 4067 4068 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4069 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4070 { 4071 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4072 const PetscInt *cone, *ornt; 4073 PetscInt *pts, *closure = NULL; 4074 DMPolytopeType ft; 4075 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4076 PetscInt dim, coneSize, c, d, clSize, cl; 4077 4078 PetscFunctionBeginHot; 4079 PetscCall(DMGetDimension(dm, &dim)); 4080 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4081 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4082 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4083 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4084 maxSize = PetscMax(coneSeries, supportSeries); 4085 if (*points) { 4086 pts = *points; 4087 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4088 c = 0; 4089 pts[c++] = point; 4090 pts[c++] = o; 4091 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4092 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4093 for (cl = 0; cl < clSize * 2; cl += 2) { 4094 pts[c++] = closure[cl]; 4095 pts[c++] = closure[cl + 1]; 4096 } 4097 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4098 for (cl = 0; cl < clSize * 2; cl += 2) { 4099 pts[c++] = closure[cl]; 4100 pts[c++] = closure[cl + 1]; 4101 } 4102 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4103 for (d = 2; d < coneSize; ++d) { 4104 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4105 pts[c++] = cone[arr[d * 2 + 0]]; 4106 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4107 } 4108 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4109 if (dim >= 3) { 4110 for (d = 2; d < coneSize; ++d) { 4111 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4112 const PetscInt *fcone, *fornt; 4113 PetscInt fconeSize, fc, i; 4114 4115 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4116 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4117 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4118 for (fc = 0; fc < fconeSize; ++fc) { 4119 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4120 const PetscInt co = farr[fc * 2 + 1]; 4121 4122 for (i = 0; i < c; i += 2) 4123 if (pts[i] == cp) break; 4124 if (i == c) { 4125 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4126 pts[c++] = cp; 4127 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4128 } 4129 } 4130 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4131 } 4132 } 4133 *numPoints = c / 2; 4134 *points = pts; 4135 PetscFunctionReturn(PETSC_SUCCESS); 4136 } 4137 4138 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4139 { 4140 DMPolytopeType ct; 4141 PetscInt *closure, *fifo; 4142 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4143 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4144 PetscInt depth, maxSize; 4145 4146 PetscFunctionBeginHot; 4147 PetscCall(DMPlexGetDepth(dm, &depth)); 4148 if (depth == 1) { 4149 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4150 PetscFunctionReturn(PETSC_SUCCESS); 4151 } 4152 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4153 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 4154 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4155 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4156 PetscFunctionReturn(PETSC_SUCCESS); 4157 } 4158 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4159 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4160 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4161 maxSize = PetscMax(coneSeries, supportSeries); 4162 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4163 if (*points) { 4164 closure = *points; 4165 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4166 closure[closureSize++] = p; 4167 closure[closureSize++] = ornt; 4168 fifo[fifoSize++] = p; 4169 fifo[fifoSize++] = ornt; 4170 fifo[fifoSize++] = ct; 4171 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4172 while (fifoSize - fifoStart) { 4173 const PetscInt q = fifo[fifoStart++]; 4174 const PetscInt o = fifo[fifoStart++]; 4175 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4176 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4177 const PetscInt *tmp, *tmpO = NULL; 4178 PetscInt tmpSize, t; 4179 4180 if (PetscDefined(USE_DEBUG)) { 4181 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4182 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 4183 } 4184 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4185 for (t = 0; t < tmpSize; ++t) { 4186 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4187 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4188 const PetscInt cp = tmp[ip]; 4189 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4190 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4191 PetscInt c; 4192 4193 /* Check for duplicate */ 4194 for (c = 0; c < closureSize; c += 2) { 4195 if (closure[c] == cp) break; 4196 } 4197 if (c == closureSize) { 4198 closure[closureSize++] = cp; 4199 closure[closureSize++] = co; 4200 fifo[fifoSize++] = cp; 4201 fifo[fifoSize++] = co; 4202 fifo[fifoSize++] = ct; 4203 } 4204 } 4205 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4206 } 4207 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4208 if (numPoints) *numPoints = closureSize / 2; 4209 if (points) *points = closure; 4210 PetscFunctionReturn(PETSC_SUCCESS); 4211 } 4212 4213 /*@C 4214 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4215 4216 Not Collective 4217 4218 Input Parameters: 4219 + dm - The `DMPLEX` 4220 . p - The mesh point 4221 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4222 4223 Input/Output Parameter: 4224 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4225 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4226 otherwise the provided array is used to hold the values 4227 4228 Output Parameter: 4229 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4230 4231 Level: beginner 4232 4233 Note: 4234 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4235 4236 Fortran Notes: 4237 `points` must be declared with 4238 .vb 4239 PetscInt, pointer :: points(:) 4240 .ve 4241 and is always allocated by the function. 4242 4243 Pass `PETSC_NULL_INTEGER` for `numPoints` if it is not needed 4244 4245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4246 @*/ 4247 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4248 { 4249 PetscFunctionBeginHot; 4250 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4251 if (numPoints) PetscAssertPointer(numPoints, 4); 4252 if (points) PetscAssertPointer(points, 5); 4253 if (PetscDefined(USE_DEBUG)) { 4254 PetscInt pStart, pEnd; 4255 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4256 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4257 } 4258 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4259 PetscFunctionReturn(PETSC_SUCCESS); 4260 } 4261 4262 /*@C 4263 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4264 4265 Not Collective 4266 4267 Input Parameters: 4268 + dm - The `DMPLEX` 4269 . p - The mesh point 4270 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4271 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4272 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4273 4274 Level: beginner 4275 4276 Note: 4277 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4278 4279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4280 @*/ 4281 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4282 { 4283 PetscFunctionBeginHot; 4284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4285 if (numPoints) *numPoints = 0; 4286 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4287 PetscFunctionReturn(PETSC_SUCCESS); 4288 } 4289 4290 /*@ 4291 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4292 4293 Not Collective 4294 4295 Input Parameter: 4296 . dm - The `DMPLEX` 4297 4298 Output Parameters: 4299 + maxConeSize - The maximum number of in-edges 4300 - maxSupportSize - The maximum number of out-edges 4301 4302 Level: beginner 4303 4304 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4305 @*/ 4306 PetscErrorCode DMPlexGetMaxSizes(DM dm, PeOp PetscInt *maxConeSize, PeOp PetscInt *maxSupportSize) 4307 { 4308 DM_Plex *mesh = (DM_Plex *)dm->data; 4309 4310 PetscFunctionBegin; 4311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4312 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4313 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4314 PetscFunctionReturn(PETSC_SUCCESS); 4315 } 4316 4317 PetscErrorCode DMSetUp_Plex(DM dm) 4318 { 4319 DM_Plex *mesh = (DM_Plex *)dm->data; 4320 PetscInt size, maxSupportSize; 4321 4322 PetscFunctionBegin; 4323 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4324 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4325 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4326 PetscCall(PetscMalloc1(size, &mesh->cones)); 4327 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4328 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4329 if (maxSupportSize) { 4330 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4331 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4332 PetscCall(PetscMalloc1(size, &mesh->supports)); 4333 } 4334 PetscFunctionReturn(PETSC_SUCCESS); 4335 } 4336 4337 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4338 { 4339 PetscFunctionBegin; 4340 if (subdm) PetscCall(DMClone(dm, subdm)); 4341 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4342 if (subdm) (*subdm)->useNatural = dm->useNatural; 4343 if (dm->useNatural && dm->sfMigration) { 4344 PetscSF sfNatural; 4345 4346 (*subdm)->sfMigration = dm->sfMigration; 4347 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4348 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4349 (*subdm)->sfNatural = sfNatural; 4350 } 4351 PetscFunctionReturn(PETSC_SUCCESS); 4352 } 4353 4354 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4355 { 4356 PetscInt i = 0; 4357 4358 PetscFunctionBegin; 4359 PetscCall(DMClone(dms[0], superdm)); 4360 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4361 (*superdm)->useNatural = PETSC_FALSE; 4362 for (i = 0; i < len; i++) { 4363 if (dms[i]->useNatural && dms[i]->sfMigration) { 4364 PetscSF sfNatural; 4365 4366 (*superdm)->sfMigration = dms[i]->sfMigration; 4367 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4368 (*superdm)->useNatural = PETSC_TRUE; 4369 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4370 (*superdm)->sfNatural = sfNatural; 4371 break; 4372 } 4373 } 4374 PetscFunctionReturn(PETSC_SUCCESS); 4375 } 4376 4377 /*@ 4378 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4379 4380 Not Collective 4381 4382 Input Parameter: 4383 . dm - The `DMPLEX` 4384 4385 Level: beginner 4386 4387 Note: 4388 This should be called after all calls to `DMPlexSetCone()` 4389 4390 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4391 @*/ 4392 PetscErrorCode DMPlexSymmetrize(DM dm) 4393 { 4394 DM_Plex *mesh = (DM_Plex *)dm->data; 4395 PetscInt *offsets; 4396 PetscInt supportSize; 4397 PetscInt pStart, pEnd, p; 4398 4399 PetscFunctionBegin; 4400 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4401 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4402 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4403 /* Calculate support sizes */ 4404 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4405 for (p = pStart; p < pEnd; ++p) { 4406 PetscInt dof, off, c; 4407 4408 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4409 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4410 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4411 } 4412 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4413 /* Calculate supports */ 4414 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4415 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4416 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4417 for (p = pStart; p < pEnd; ++p) { 4418 PetscInt dof, off, c; 4419 4420 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4421 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4422 for (c = off; c < off + dof; ++c) { 4423 const PetscInt q = mesh->cones[c]; 4424 PetscInt offS; 4425 4426 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4427 4428 mesh->supports[offS + offsets[q]] = p; 4429 ++offsets[q]; 4430 } 4431 } 4432 PetscCall(PetscFree(offsets)); 4433 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4434 PetscFunctionReturn(PETSC_SUCCESS); 4435 } 4436 4437 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4438 { 4439 IS stratumIS; 4440 4441 PetscFunctionBegin; 4442 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4443 if (PetscDefined(USE_DEBUG)) { 4444 PetscInt qStart, qEnd, numLevels, level; 4445 PetscBool overlap = PETSC_FALSE; 4446 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4447 for (level = 0; level < numLevels; level++) { 4448 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4449 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4450 overlap = PETSC_TRUE; 4451 break; 4452 } 4453 } 4454 PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 4455 } 4456 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4457 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4458 PetscCall(ISDestroy(&stratumIS)); 4459 PetscFunctionReturn(PETSC_SUCCESS); 4460 } 4461 4462 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4463 { 4464 PetscInt *pMin, *pMax; 4465 PetscInt pStart, pEnd; 4466 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4467 4468 PetscFunctionBegin; 4469 { 4470 DMLabel label2; 4471 4472 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4473 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4474 } 4475 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4476 for (PetscInt p = pStart; p < pEnd; ++p) { 4477 DMPolytopeType ct; 4478 4479 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4480 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4481 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4482 } 4483 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4484 for (PetscInt d = dmin; d <= dmax; ++d) { 4485 pMin[d] = PETSC_INT_MAX; 4486 pMax[d] = PETSC_INT_MIN; 4487 } 4488 for (PetscInt p = pStart; p < pEnd; ++p) { 4489 DMPolytopeType ct; 4490 PetscInt d; 4491 4492 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4493 d = DMPolytopeTypeGetDim(ct); 4494 pMin[d] = PetscMin(p, pMin[d]); 4495 pMax[d] = PetscMax(p, pMax[d]); 4496 } 4497 for (PetscInt d = dmin; d <= dmax; ++d) { 4498 if (pMin[d] > pMax[d]) continue; 4499 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4500 } 4501 PetscCall(PetscFree2(pMin, pMax)); 4502 PetscFunctionReturn(PETSC_SUCCESS); 4503 } 4504 4505 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4506 { 4507 PetscInt pStart, pEnd; 4508 PetscInt numRoots = 0, numLeaves = 0; 4509 4510 PetscFunctionBegin; 4511 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4512 { 4513 /* Initialize roots and count leaves */ 4514 PetscInt sMin = PETSC_INT_MAX; 4515 PetscInt sMax = PETSC_INT_MIN; 4516 PetscInt coneSize, supportSize; 4517 4518 for (PetscInt p = pStart; p < pEnd; ++p) { 4519 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4520 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4521 if (!coneSize && supportSize) { 4522 sMin = PetscMin(p, sMin); 4523 sMax = PetscMax(p, sMax); 4524 ++numRoots; 4525 } else if (!supportSize && coneSize) { 4526 ++numLeaves; 4527 } else if (!supportSize && !coneSize) { 4528 /* Isolated points */ 4529 sMin = PetscMin(p, sMin); 4530 sMax = PetscMax(p, sMax); 4531 } 4532 } 4533 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4534 } 4535 4536 if (numRoots + numLeaves == (pEnd - pStart)) { 4537 PetscInt sMin = PETSC_INT_MAX; 4538 PetscInt sMax = PETSC_INT_MIN; 4539 PetscInt coneSize, supportSize; 4540 4541 for (PetscInt p = pStart; p < pEnd; ++p) { 4542 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4543 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4544 if (!supportSize && coneSize) { 4545 sMin = PetscMin(p, sMin); 4546 sMax = PetscMax(p, sMax); 4547 } 4548 } 4549 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4550 } else { 4551 PetscInt level = 0; 4552 PetscInt qStart, qEnd; 4553 4554 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4555 while (qEnd > qStart) { 4556 PetscInt sMin = PETSC_INT_MAX; 4557 PetscInt sMax = PETSC_INT_MIN; 4558 4559 for (PetscInt q = qStart; q < qEnd; ++q) { 4560 const PetscInt *support; 4561 PetscInt supportSize; 4562 4563 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4564 PetscCall(DMPlexGetSupport(dm, q, &support)); 4565 for (PetscInt s = 0; s < supportSize; ++s) { 4566 sMin = PetscMin(support[s], sMin); 4567 sMax = PetscMax(support[s], sMax); 4568 } 4569 } 4570 PetscCall(DMLabelGetNumValues(label, &level)); 4571 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4572 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4573 } 4574 } 4575 PetscFunctionReturn(PETSC_SUCCESS); 4576 } 4577 4578 /*@ 4579 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4580 4581 Collective 4582 4583 Input Parameter: 4584 . dm - The `DMPLEX` 4585 4586 Level: beginner 4587 4588 Notes: 4589 The strata group all points of the same grade, and this function calculates the strata. This 4590 grade can be seen as the height (or depth) of the point in the DAG. 4591 4592 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4593 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4594 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4595 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4596 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4597 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4598 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4599 4600 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4601 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4602 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 4603 to interpolate only that one (e0), so that 4604 .vb 4605 cone(c0) = {e0, v2} 4606 cone(e0) = {v0, v1} 4607 .ve 4608 If `DMPlexStratify()` is run on this mesh, it will give depths 4609 .vb 4610 depth 0 = {v0, v1, v2} 4611 depth 1 = {e0, c0} 4612 .ve 4613 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4614 4615 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4616 4617 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4618 @*/ 4619 PetscErrorCode DMPlexStratify(DM dm) 4620 { 4621 DM_Plex *mesh = (DM_Plex *)dm->data; 4622 DMLabel label; 4623 PetscBool flg = PETSC_FALSE; 4624 4625 PetscFunctionBegin; 4626 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4627 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4628 4629 // Create depth label 4630 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4631 PetscCall(DMCreateLabel(dm, "depth")); 4632 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4633 4634 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4635 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4636 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4637 4638 { /* just in case there is an empty process */ 4639 PetscInt numValues, maxValues = 0, v; 4640 4641 PetscCall(DMLabelGetNumValues(label, &numValues)); 4642 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4643 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4644 } 4645 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4646 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4647 PetscFunctionReturn(PETSC_SUCCESS); 4648 } 4649 4650 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4651 { 4652 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4653 PetscInt dim, depth, pheight, coneSize; 4654 PetscBool preferTensor; 4655 4656 PetscFunctionBeginHot; 4657 PetscCall(DMGetDimension(dm, &dim)); 4658 PetscCall(DMPlexGetDepth(dm, &depth)); 4659 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4660 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4661 pheight = depth - pdepth; 4662 if (depth <= 1) { 4663 switch (pdepth) { 4664 case 0: 4665 ct = DM_POLYTOPE_POINT; 4666 break; 4667 case 1: 4668 switch (coneSize) { 4669 case 2: 4670 ct = DM_POLYTOPE_SEGMENT; 4671 break; 4672 case 3: 4673 ct = DM_POLYTOPE_TRIANGLE; 4674 break; 4675 case 4: 4676 switch (dim) { 4677 case 2: 4678 ct = DM_POLYTOPE_QUADRILATERAL; 4679 break; 4680 case 3: 4681 ct = DM_POLYTOPE_TETRAHEDRON; 4682 break; 4683 default: 4684 break; 4685 } 4686 break; 4687 case 5: 4688 ct = DM_POLYTOPE_PYRAMID; 4689 break; 4690 case 6: 4691 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4692 break; 4693 case 8: 4694 ct = DM_POLYTOPE_HEXAHEDRON; 4695 break; 4696 default: 4697 break; 4698 } 4699 } 4700 } else { 4701 if (pdepth == 0) { 4702 ct = DM_POLYTOPE_POINT; 4703 } else if (pheight == 0) { 4704 switch (dim) { 4705 case 1: 4706 switch (coneSize) { 4707 case 2: 4708 ct = DM_POLYTOPE_SEGMENT; 4709 break; 4710 default: 4711 break; 4712 } 4713 break; 4714 case 2: 4715 switch (coneSize) { 4716 case 3: 4717 ct = DM_POLYTOPE_TRIANGLE; 4718 break; 4719 case 4: 4720 ct = DM_POLYTOPE_QUADRILATERAL; 4721 break; 4722 default: 4723 break; 4724 } 4725 break; 4726 case 3: 4727 switch (coneSize) { 4728 case 4: 4729 ct = DM_POLYTOPE_TETRAHEDRON; 4730 break; 4731 case 5: { 4732 const PetscInt *cone; 4733 PetscInt faceConeSize; 4734 4735 PetscCall(DMPlexGetCone(dm, p, &cone)); 4736 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4737 switch (faceConeSize) { 4738 case 3: 4739 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4740 break; 4741 case 4: 4742 ct = DM_POLYTOPE_PYRAMID; 4743 break; 4744 } 4745 } break; 4746 case 6: 4747 ct = DM_POLYTOPE_HEXAHEDRON; 4748 break; 4749 default: 4750 break; 4751 } 4752 break; 4753 default: 4754 break; 4755 } 4756 } else if (pheight > 0) { 4757 switch (coneSize) { 4758 case 2: 4759 ct = DM_POLYTOPE_SEGMENT; 4760 break; 4761 case 3: 4762 ct = DM_POLYTOPE_TRIANGLE; 4763 break; 4764 case 4: 4765 ct = DM_POLYTOPE_QUADRILATERAL; 4766 break; 4767 default: 4768 break; 4769 } 4770 } 4771 } 4772 *pt = ct; 4773 PetscFunctionReturn(PETSC_SUCCESS); 4774 } 4775 4776 /*@ 4777 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4778 4779 Collective 4780 4781 Input Parameter: 4782 . dm - The `DMPLEX` 4783 4784 Level: developer 4785 4786 Note: 4787 This function is normally called automatically when a cell type is requested. It creates an 4788 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4789 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4790 4791 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4792 4793 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4794 @*/ 4795 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4796 { 4797 DM_Plex *mesh; 4798 DMLabel ctLabel; 4799 PetscInt pStart, pEnd, p; 4800 4801 PetscFunctionBegin; 4802 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4803 mesh = (DM_Plex *)dm->data; 4804 PetscCall(DMCreateLabel(dm, "celltype")); 4805 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4806 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4807 PetscCall(PetscFree(mesh->cellTypes)); 4808 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4809 for (p = pStart; p < pEnd; ++p) { 4810 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4811 PetscInt pdepth; 4812 4813 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4814 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4815 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4816 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4817 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4818 } 4819 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4820 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4821 PetscFunctionReturn(PETSC_SUCCESS); 4822 } 4823 4824 /*@C 4825 DMPlexGetJoin - Get an array for the join of the set of points 4826 4827 Not Collective 4828 4829 Input Parameters: 4830 + dm - The `DMPLEX` object 4831 . numPoints - The number of input points for the join 4832 - points - The input points 4833 4834 Output Parameters: 4835 + numCoveredPoints - The number of points in the join 4836 - coveredPoints - The points in the join 4837 4838 Level: intermediate 4839 4840 Note: 4841 Currently, this is restricted to a single level join 4842 4843 Fortran Notes: 4844 `converedPoints` must be declared with 4845 .vb 4846 PetscInt, pointer :: coveredPints(:) 4847 .ve 4848 4849 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4850 @*/ 4851 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4852 { 4853 DM_Plex *mesh = (DM_Plex *)dm->data; 4854 PetscInt *join[2]; 4855 PetscInt joinSize, i = 0; 4856 PetscInt dof, off, p, c, m; 4857 PetscInt maxSupportSize; 4858 4859 PetscFunctionBegin; 4860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4861 PetscAssertPointer(points, 3); 4862 PetscAssertPointer(numCoveredPoints, 4); 4863 PetscAssertPointer(coveredPoints, 5); 4864 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4865 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4866 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4867 /* Copy in support of first point */ 4868 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4869 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4870 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4871 /* Check each successive support */ 4872 for (p = 1; p < numPoints; ++p) { 4873 PetscInt newJoinSize = 0; 4874 4875 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4876 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4877 for (c = 0; c < dof; ++c) { 4878 const PetscInt point = mesh->supports[off + c]; 4879 4880 for (m = 0; m < joinSize; ++m) { 4881 if (point == join[i][m]) { 4882 join[1 - i][newJoinSize++] = point; 4883 break; 4884 } 4885 } 4886 } 4887 joinSize = newJoinSize; 4888 i = 1 - i; 4889 } 4890 *numCoveredPoints = joinSize; 4891 *coveredPoints = join[i]; 4892 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4893 PetscFunctionReturn(PETSC_SUCCESS); 4894 } 4895 4896 /*@C 4897 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4898 4899 Not Collective 4900 4901 Input Parameters: 4902 + dm - The `DMPLEX` object 4903 . numPoints - The number of input points for the join 4904 - points - The input points 4905 4906 Output Parameters: 4907 + numCoveredPoints - The number of points in the join 4908 - coveredPoints - The points in the join 4909 4910 Level: intermediate 4911 4912 Fortran Notes: 4913 `converedPoints` must be declared with 4914 .vb 4915 PetscInt, pointer :: coveredPoints(:) 4916 .ve 4917 4918 Pass `PETSC_NULL_INTEGER` for `numCoveredPoints` if it is not needed 4919 4920 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4921 @*/ 4922 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4923 { 4924 PetscFunctionBegin; 4925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4926 if (points) PetscAssertPointer(points, 3); 4927 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4928 PetscAssertPointer(coveredPoints, 5); 4929 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4930 if (numCoveredPoints) *numCoveredPoints = 0; 4931 PetscFunctionReturn(PETSC_SUCCESS); 4932 } 4933 4934 /*@C 4935 DMPlexGetFullJoin - Get an array for the join of the set of points 4936 4937 Not Collective 4938 4939 Input Parameters: 4940 + dm - The `DMPLEX` object 4941 . numPoints - The number of input points for the join 4942 - points - The input points, its length is `numPoints` 4943 4944 Output Parameters: 4945 + numCoveredPoints - The number of points in the join 4946 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4947 4948 Level: intermediate 4949 4950 Fortran Notes: 4951 .vb 4952 PetscInt, pointer :: coveredPints(:) 4953 .ve 4954 4955 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4956 @*/ 4957 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4958 { 4959 PetscInt *offsets, **closures; 4960 PetscInt *join[2]; 4961 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4962 PetscInt p, d, c, m, ms; 4963 4964 PetscFunctionBegin; 4965 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4966 PetscAssertPointer(points, 3); 4967 PetscAssertPointer(numCoveredPoints, 4); 4968 PetscAssertPointer(coveredPoints, 5); 4969 4970 PetscCall(DMPlexGetDepth(dm, &depth)); 4971 PetscCall(PetscCalloc1(numPoints, &closures)); 4972 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4973 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4974 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4975 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4976 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4977 4978 for (p = 0; p < numPoints; ++p) { 4979 PetscInt closureSize; 4980 4981 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4982 4983 offsets[p * (depth + 2) + 0] = 0; 4984 for (d = 0; d < depth + 1; ++d) { 4985 PetscInt pStart, pEnd, i; 4986 4987 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4988 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4989 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4990 offsets[p * (depth + 2) + d + 1] = i; 4991 break; 4992 } 4993 } 4994 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4995 } 4996 PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize); 4997 } 4998 for (d = 0; d < depth + 1; ++d) { 4999 PetscInt dof; 5000 5001 /* Copy in support of first point */ 5002 dof = offsets[d + 1] - offsets[d]; 5003 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 5004 /* Check each successive cone */ 5005 for (p = 1; p < numPoints && joinSize; ++p) { 5006 PetscInt newJoinSize = 0; 5007 5008 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 5009 for (c = 0; c < dof; ++c) { 5010 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 5011 5012 for (m = 0; m < joinSize; ++m) { 5013 if (point == join[i][m]) { 5014 join[1 - i][newJoinSize++] = point; 5015 break; 5016 } 5017 } 5018 } 5019 joinSize = newJoinSize; 5020 i = 1 - i; 5021 } 5022 if (joinSize) break; 5023 } 5024 *numCoveredPoints = joinSize; 5025 *coveredPoints = join[i]; 5026 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 5027 PetscCall(PetscFree(closures)); 5028 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 5029 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 5030 PetscFunctionReturn(PETSC_SUCCESS); 5031 } 5032 5033 /*@C 5034 DMPlexGetMeet - Get an array for the meet of the set of points 5035 5036 Not Collective 5037 5038 Input Parameters: 5039 + dm - The `DMPLEX` object 5040 . numPoints - The number of input points for the meet 5041 - points - The input points, of length `numPoints` 5042 5043 Output Parameters: 5044 + numCoveringPoints - The number of points in the meet 5045 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5046 5047 Level: intermediate 5048 5049 Note: 5050 Currently, this is restricted to a single level meet 5051 5052 Fortran Note: 5053 `coveringPoints` must be declared with 5054 .vb 5055 PetscInt, pointer :: coveringPoints(:) 5056 .ve 5057 5058 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5059 @*/ 5060 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5061 { 5062 DM_Plex *mesh = (DM_Plex *)dm->data; 5063 PetscInt *meet[2]; 5064 PetscInt meetSize, i = 0; 5065 PetscInt dof, off, p, c, m; 5066 PetscInt maxConeSize; 5067 5068 PetscFunctionBegin; 5069 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5070 PetscAssertPointer(points, 3); 5071 PetscAssertPointer(numCoveringPoints, 4); 5072 PetscAssertPointer(coveringPoints, 5); 5073 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5074 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5075 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5076 /* Copy in cone of first point */ 5077 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5078 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5079 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5080 /* Check each successive cone */ 5081 for (p = 1; p < numPoints; ++p) { 5082 PetscInt newMeetSize = 0; 5083 5084 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5085 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5086 for (c = 0; c < dof; ++c) { 5087 const PetscInt point = mesh->cones[off + c]; 5088 5089 for (m = 0; m < meetSize; ++m) { 5090 if (point == meet[i][m]) { 5091 meet[1 - i][newMeetSize++] = point; 5092 break; 5093 } 5094 } 5095 } 5096 meetSize = newMeetSize; 5097 i = 1 - i; 5098 } 5099 *numCoveringPoints = meetSize; 5100 *coveringPoints = meet[i]; 5101 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5102 PetscFunctionReturn(PETSC_SUCCESS); 5103 } 5104 5105 /*@C 5106 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5107 5108 Not Collective 5109 5110 Input Parameters: 5111 + dm - The `DMPLEX` object 5112 . numPoints - The number of input points for the meet 5113 - points - The input points 5114 5115 Output Parameters: 5116 + numCoveredPoints - The number of points in the meet 5117 - coveredPoints - The points in the meet 5118 5119 Level: intermediate 5120 5121 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5122 @*/ 5123 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5124 { 5125 PetscFunctionBegin; 5126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5127 if (points) PetscAssertPointer(points, 3); 5128 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5129 PetscAssertPointer(coveredPoints, 5); 5130 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5131 if (numCoveredPoints) *numCoveredPoints = 0; 5132 PetscFunctionReturn(PETSC_SUCCESS); 5133 } 5134 5135 /*@C 5136 DMPlexGetFullMeet - Get an array for the meet of the set of points 5137 5138 Not Collective 5139 5140 Input Parameters: 5141 + dm - The `DMPLEX` object 5142 . numPoints - The number of input points for the meet 5143 - points - The input points, of length `numPoints` 5144 5145 Output Parameters: 5146 + numCoveredPoints - The number of points in the meet 5147 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5148 5149 Level: intermediate 5150 5151 Fortran Notes: 5152 `coveredPoints` must be declared with 5153 .vb 5154 PetscInt, pointer :: coveredPoints(:) 5155 .ve 5156 5157 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5158 @*/ 5159 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5160 { 5161 PetscInt *offsets, **closures; 5162 PetscInt *meet[2]; 5163 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5164 PetscInt p, h, c, m, mc; 5165 5166 PetscFunctionBegin; 5167 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5168 PetscAssertPointer(points, 3); 5169 PetscAssertPointer(numCoveredPoints, 4); 5170 PetscAssertPointer(coveredPoints, 5); 5171 5172 PetscCall(DMPlexGetDepth(dm, &height)); 5173 PetscCall(PetscMalloc1(numPoints, &closures)); 5174 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5175 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5176 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5177 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5178 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5179 5180 for (p = 0; p < numPoints; ++p) { 5181 PetscInt closureSize; 5182 5183 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5184 5185 offsets[p * (height + 2) + 0] = 0; 5186 for (h = 0; h < height + 1; ++h) { 5187 PetscInt pStart, pEnd, i; 5188 5189 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5190 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5191 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5192 offsets[p * (height + 2) + h + 1] = i; 5193 break; 5194 } 5195 } 5196 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5197 } 5198 PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize); 5199 } 5200 for (h = 0; h < height + 1; ++h) { 5201 PetscInt dof; 5202 5203 /* Copy in cone of first point */ 5204 dof = offsets[h + 1] - offsets[h]; 5205 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5206 /* Check each successive cone */ 5207 for (p = 1; p < numPoints && meetSize; ++p) { 5208 PetscInt newMeetSize = 0; 5209 5210 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5211 for (c = 0; c < dof; ++c) { 5212 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5213 5214 for (m = 0; m < meetSize; ++m) { 5215 if (point == meet[i][m]) { 5216 meet[1 - i][newMeetSize++] = point; 5217 break; 5218 } 5219 } 5220 } 5221 meetSize = newMeetSize; 5222 i = 1 - i; 5223 } 5224 if (meetSize) break; 5225 } 5226 *numCoveredPoints = meetSize; 5227 *coveredPoints = meet[i]; 5228 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5229 PetscCall(PetscFree(closures)); 5230 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5231 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5232 PetscFunctionReturn(PETSC_SUCCESS); 5233 } 5234 5235 /*@ 5236 DMPlexEqual - Determine if two `DM` have the same topology 5237 5238 Not Collective 5239 5240 Input Parameters: 5241 + dmA - A `DMPLEX` object 5242 - dmB - A `DMPLEX` object 5243 5244 Output Parameter: 5245 . equal - `PETSC_TRUE` if the topologies are identical 5246 5247 Level: intermediate 5248 5249 Note: 5250 We are not solving graph isomorphism, so we do not permute. 5251 5252 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5253 @*/ 5254 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5255 { 5256 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5257 5258 PetscFunctionBegin; 5259 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5260 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5261 PetscAssertPointer(equal, 3); 5262 5263 *equal = PETSC_FALSE; 5264 PetscCall(DMPlexGetDepth(dmA, &depth)); 5265 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5266 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5267 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5268 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5269 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5270 for (p = pStart; p < pEnd; ++p) { 5271 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5272 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5273 5274 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5275 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5276 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5277 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5278 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5279 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5280 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5281 for (c = 0; c < coneSize; ++c) { 5282 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5283 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5284 } 5285 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5286 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5287 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5288 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5289 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5290 for (s = 0; s < supportSize; ++s) { 5291 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5292 } 5293 } 5294 *equal = PETSC_TRUE; 5295 PetscFunctionReturn(PETSC_SUCCESS); 5296 } 5297 5298 /*@ 5299 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5300 5301 Not Collective 5302 5303 Input Parameters: 5304 + dm - The `DMPLEX` 5305 . cellDim - The cell dimension 5306 - numCorners - The number of vertices on a cell 5307 5308 Output Parameter: 5309 . numFaceVertices - The number of vertices on a face 5310 5311 Level: developer 5312 5313 Note: 5314 Of course this can only work for a restricted set of symmetric shapes 5315 5316 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5317 @*/ 5318 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5319 { 5320 MPI_Comm comm; 5321 5322 PetscFunctionBegin; 5323 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5324 PetscAssertPointer(numFaceVertices, 4); 5325 switch (cellDim) { 5326 case 0: 5327 *numFaceVertices = 0; 5328 break; 5329 case 1: 5330 *numFaceVertices = 1; 5331 break; 5332 case 2: 5333 switch (numCorners) { 5334 case 3: /* triangle */ 5335 *numFaceVertices = 2; /* Edge has 2 vertices */ 5336 break; 5337 case 4: /* quadrilateral */ 5338 *numFaceVertices = 2; /* Edge has 2 vertices */ 5339 break; 5340 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5341 *numFaceVertices = 3; /* Edge has 3 vertices */ 5342 break; 5343 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5344 *numFaceVertices = 3; /* Edge has 3 vertices */ 5345 break; 5346 default: 5347 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5348 } 5349 break; 5350 case 3: 5351 switch (numCorners) { 5352 case 4: /* tetradehdron */ 5353 *numFaceVertices = 3; /* Face has 3 vertices */ 5354 break; 5355 case 6: /* tet cohesive cells */ 5356 *numFaceVertices = 4; /* Face has 4 vertices */ 5357 break; 5358 case 8: /* hexahedron */ 5359 *numFaceVertices = 4; /* Face has 4 vertices */ 5360 break; 5361 case 9: /* tet cohesive Lagrange cells */ 5362 *numFaceVertices = 6; /* Face has 6 vertices */ 5363 break; 5364 case 10: /* quadratic tetrahedron */ 5365 *numFaceVertices = 6; /* Face has 6 vertices */ 5366 break; 5367 case 12: /* hex cohesive Lagrange cells */ 5368 *numFaceVertices = 6; /* Face has 6 vertices */ 5369 break; 5370 case 18: /* quadratic tet cohesive Lagrange cells */ 5371 *numFaceVertices = 6; /* Face has 6 vertices */ 5372 break; 5373 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5374 *numFaceVertices = 9; /* Face has 9 vertices */ 5375 break; 5376 default: 5377 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5378 } 5379 break; 5380 default: 5381 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5382 } 5383 PetscFunctionReturn(PETSC_SUCCESS); 5384 } 5385 5386 /*@ 5387 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5388 5389 Not Collective 5390 5391 Input Parameter: 5392 . dm - The `DMPLEX` object 5393 5394 Output Parameter: 5395 . depthLabel - The `DMLabel` recording point depth 5396 5397 Level: developer 5398 5399 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5400 @*/ 5401 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5402 { 5403 PetscFunctionBegin; 5404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5405 PetscAssertPointer(depthLabel, 2); 5406 *depthLabel = dm->depthLabel; 5407 PetscFunctionReturn(PETSC_SUCCESS); 5408 } 5409 5410 /*@ 5411 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5412 5413 Not Collective 5414 5415 Input Parameter: 5416 . dm - The `DMPLEX` object 5417 5418 Output Parameter: 5419 . depth - The number of strata (breadth first levels) in the DAG 5420 5421 Level: developer 5422 5423 Notes: 5424 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5425 5426 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5427 5428 An empty mesh gives -1. 5429 5430 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5431 @*/ 5432 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5433 { 5434 DM_Plex *mesh = (DM_Plex *)dm->data; 5435 DMLabel label; 5436 PetscInt d = -1; 5437 5438 PetscFunctionBegin; 5439 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5440 PetscAssertPointer(depth, 2); 5441 if (mesh->tr) { 5442 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5443 } else { 5444 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5445 // Allow missing depths 5446 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5447 *depth = d; 5448 } 5449 PetscFunctionReturn(PETSC_SUCCESS); 5450 } 5451 5452 /*@ 5453 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5454 5455 Not Collective 5456 5457 Input Parameters: 5458 + dm - The `DMPLEX` object 5459 - depth - The requested depth 5460 5461 Output Parameters: 5462 + start - The first point at this `depth` 5463 - end - One beyond the last point at this `depth` 5464 5465 Level: developer 5466 5467 Notes: 5468 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5469 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5470 higher dimension, e.g., "edges". 5471 5472 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5473 @*/ 5474 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PeOp PetscInt *start, PeOp PetscInt *end) 5475 { 5476 DM_Plex *mesh = (DM_Plex *)dm->data; 5477 DMLabel label; 5478 PetscInt pStart, pEnd; 5479 5480 PetscFunctionBegin; 5481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5482 if (start) { 5483 PetscAssertPointer(start, 3); 5484 *start = 0; 5485 } 5486 if (end) { 5487 PetscAssertPointer(end, 4); 5488 *end = 0; 5489 } 5490 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5491 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5492 if (depth < 0) { 5493 if (start) *start = pStart; 5494 if (end) *end = pEnd; 5495 PetscFunctionReturn(PETSC_SUCCESS); 5496 } 5497 if (mesh->tr) { 5498 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5499 } else { 5500 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5501 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5502 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5503 } 5504 PetscFunctionReturn(PETSC_SUCCESS); 5505 } 5506 5507 /*@ 5508 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5509 5510 Not Collective 5511 5512 Input Parameters: 5513 + dm - The `DMPLEX` object 5514 - height - The requested height 5515 5516 Output Parameters: 5517 + start - The first point at this `height` 5518 - end - One beyond the last point at this `height` 5519 5520 Level: developer 5521 5522 Notes: 5523 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5524 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5525 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5526 5527 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5528 @*/ 5529 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PeOp PetscInt *start, PeOp PetscInt *end) 5530 { 5531 DMLabel label; 5532 PetscInt depth, pStart, pEnd; 5533 5534 PetscFunctionBegin; 5535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5536 if (start) { 5537 PetscAssertPointer(start, 3); 5538 *start = 0; 5539 } 5540 if (end) { 5541 PetscAssertPointer(end, 4); 5542 *end = 0; 5543 } 5544 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5545 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5546 if (height < 0) { 5547 if (start) *start = pStart; 5548 if (end) *end = pEnd; 5549 PetscFunctionReturn(PETSC_SUCCESS); 5550 } 5551 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5552 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5553 else PetscCall(DMGetDimension(dm, &depth)); 5554 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5555 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5556 PetscFunctionReturn(PETSC_SUCCESS); 5557 } 5558 5559 /*@ 5560 DMPlexGetPointDepth - Get the `depth` of a given point 5561 5562 Not Collective 5563 5564 Input Parameters: 5565 + dm - The `DMPLEX` object 5566 - point - The point 5567 5568 Output Parameter: 5569 . depth - The depth of the `point` 5570 5571 Level: intermediate 5572 5573 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5574 @*/ 5575 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5576 { 5577 PetscFunctionBegin; 5578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5579 PetscAssertPointer(depth, 3); 5580 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5581 PetscFunctionReturn(PETSC_SUCCESS); 5582 } 5583 5584 /*@ 5585 DMPlexGetPointHeight - Get the `height` of a given point 5586 5587 Not Collective 5588 5589 Input Parameters: 5590 + dm - The `DMPLEX` object 5591 - point - The point 5592 5593 Output Parameter: 5594 . height - The height of the `point` 5595 5596 Level: intermediate 5597 5598 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5599 @*/ 5600 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5601 { 5602 PetscInt n, pDepth; 5603 5604 PetscFunctionBegin; 5605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5606 PetscAssertPointer(height, 3); 5607 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5608 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5609 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5610 PetscFunctionReturn(PETSC_SUCCESS); 5611 } 5612 5613 /*@ 5614 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5615 5616 Not Collective 5617 5618 Input Parameter: 5619 . dm - The `DMPLEX` object 5620 5621 Output Parameter: 5622 . celltypeLabel - The `DMLabel` recording cell polytope type 5623 5624 Level: developer 5625 5626 Note: 5627 This function will trigger automatica computation of cell types. This can be disabled by calling 5628 `DMCreateLabel`(dm, "celltype") beforehand. 5629 5630 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5631 @*/ 5632 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5633 { 5634 PetscFunctionBegin; 5635 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5636 PetscAssertPointer(celltypeLabel, 2); 5637 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5638 *celltypeLabel = dm->celltypeLabel; 5639 PetscFunctionReturn(PETSC_SUCCESS); 5640 } 5641 5642 /*@ 5643 DMPlexGetCellType - Get the polytope type of a given cell 5644 5645 Not Collective 5646 5647 Input Parameters: 5648 + dm - The `DMPLEX` object 5649 - cell - The cell 5650 5651 Output Parameter: 5652 . celltype - The polytope type of the cell 5653 5654 Level: intermediate 5655 5656 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5657 @*/ 5658 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5659 { 5660 DM_Plex *mesh = (DM_Plex *)dm->data; 5661 DMLabel label; 5662 PetscInt ct; 5663 5664 PetscFunctionBegin; 5665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5666 PetscAssertPointer(celltype, 3); 5667 if (mesh->tr) { 5668 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5669 } else { 5670 PetscInt pStart, pEnd; 5671 5672 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5673 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5674 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5675 if (pEnd <= pStart) { 5676 *celltype = DM_POLYTOPE_UNKNOWN; 5677 PetscFunctionReturn(PETSC_SUCCESS); 5678 } 5679 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5680 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5681 for (PetscInt p = pStart; p < pEnd; p++) { 5682 PetscCall(DMLabelGetValue(label, p, &ct)); 5683 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5684 } 5685 } 5686 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5687 if (PetscDefined(USE_DEBUG)) { 5688 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5689 PetscCall(DMLabelGetValue(label, cell, &ct)); 5690 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5691 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5692 } 5693 } 5694 PetscFunctionReturn(PETSC_SUCCESS); 5695 } 5696 5697 /*@ 5698 DMPlexSetCellType - Set the polytope type of a given cell 5699 5700 Not Collective 5701 5702 Input Parameters: 5703 + dm - The `DMPLEX` object 5704 . cell - The cell 5705 - celltype - The polytope type of the cell 5706 5707 Level: advanced 5708 5709 Note: 5710 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5711 is executed. This function will override the computed type. However, if automatic classification will not succeed 5712 and a user wants to manually specify all types, the classification must be disabled by calling 5713 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5714 5715 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5716 @*/ 5717 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5718 { 5719 DM_Plex *mesh = (DM_Plex *)dm->data; 5720 DMLabel label; 5721 PetscInt pStart, pEnd; 5722 5723 PetscFunctionBegin; 5724 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5725 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5726 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5727 PetscCall(DMLabelSetValue(label, cell, celltype)); 5728 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5729 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5730 PetscFunctionReturn(PETSC_SUCCESS); 5731 } 5732 5733 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5734 { 5735 PetscSection section; 5736 PetscInt maxHeight; 5737 const char *prefix; 5738 5739 PetscFunctionBegin; 5740 PetscCall(DMClone(dm, cdm)); 5741 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5742 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5743 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5744 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5745 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5746 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5747 PetscCall(DMSetLocalSection(*cdm, section)); 5748 PetscCall(PetscSectionDestroy(§ion)); 5749 5750 PetscCall(DMSetNumFields(*cdm, 1)); 5751 PetscCall(DMCreateDS(*cdm)); 5752 (*cdm)->cloneOpts = PETSC_TRUE; 5753 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5754 PetscFunctionReturn(PETSC_SUCCESS); 5755 } 5756 5757 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5758 { 5759 Vec coordsLocal, cellCoordsLocal; 5760 DM coordsDM, cellCoordsDM; 5761 5762 PetscFunctionBegin; 5763 *field = NULL; 5764 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5765 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5766 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5767 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5768 if (coordsLocal && coordsDM) { 5769 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5770 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5771 } 5772 PetscFunctionReturn(PETSC_SUCCESS); 5773 } 5774 5775 /*@ 5776 DMPlexGetConeSection - Return a section which describes the layout of cone data 5777 5778 Not Collective 5779 5780 Input Parameter: 5781 . dm - The `DMPLEX` object 5782 5783 Output Parameter: 5784 . section - The `PetscSection` object 5785 5786 Level: developer 5787 5788 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5789 @*/ 5790 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5791 { 5792 DM_Plex *mesh = (DM_Plex *)dm->data; 5793 5794 PetscFunctionBegin; 5795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5796 if (section) *section = mesh->coneSection; 5797 PetscFunctionReturn(PETSC_SUCCESS); 5798 } 5799 5800 /*@ 5801 DMPlexGetSupportSection - Return a section which describes the layout of support data 5802 5803 Not Collective 5804 5805 Input Parameter: 5806 . dm - The `DMPLEX` object 5807 5808 Output Parameter: 5809 . section - The `PetscSection` object 5810 5811 Level: developer 5812 5813 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5814 @*/ 5815 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5816 { 5817 DM_Plex *mesh = (DM_Plex *)dm->data; 5818 5819 PetscFunctionBegin; 5820 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5821 if (section) *section = mesh->supportSection; 5822 PetscFunctionReturn(PETSC_SUCCESS); 5823 } 5824 5825 /*@C 5826 DMPlexGetCones - Return cone data 5827 5828 Not Collective 5829 5830 Input Parameter: 5831 . dm - The `DMPLEX` object 5832 5833 Output Parameter: 5834 . cones - The cone for each point 5835 5836 Level: developer 5837 5838 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5839 @*/ 5840 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5841 { 5842 DM_Plex *mesh = (DM_Plex *)dm->data; 5843 5844 PetscFunctionBegin; 5845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5846 if (cones) *cones = mesh->cones; 5847 PetscFunctionReturn(PETSC_SUCCESS); 5848 } 5849 5850 /*@C 5851 DMPlexGetConeOrientations - Return cone orientation data 5852 5853 Not Collective 5854 5855 Input Parameter: 5856 . dm - The `DMPLEX` object 5857 5858 Output Parameter: 5859 . coneOrientations - The array of cone orientations for all points 5860 5861 Level: developer 5862 5863 Notes: 5864 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5865 as returned by `DMPlexGetConeOrientation()`. 5866 5867 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5868 5869 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5870 @*/ 5871 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5872 { 5873 DM_Plex *mesh = (DM_Plex *)dm->data; 5874 5875 PetscFunctionBegin; 5876 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5877 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5878 PetscFunctionReturn(PETSC_SUCCESS); 5879 } 5880 5881 /* FEM Support */ 5882 5883 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5884 { 5885 PetscInt depth; 5886 5887 PetscFunctionBegin; 5888 PetscCall(DMPlexGetDepth(plex, &depth)); 5889 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5890 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5891 PetscFunctionReturn(PETSC_SUCCESS); 5892 } 5893 5894 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5895 { 5896 PetscInt depth; 5897 5898 PetscFunctionBegin; 5899 PetscCall(DMPlexGetDepth(plex, &depth)); 5900 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5901 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5902 PetscFunctionReturn(PETSC_SUCCESS); 5903 } 5904 5905 /* 5906 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5907 representing a line in the section. 5908 */ 5909 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5910 { 5911 PetscObject obj; 5912 PetscClassId id; 5913 PetscFE fe = NULL; 5914 5915 PetscFunctionBeginHot; 5916 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5917 PetscCall(DMGetField(dm, field, NULL, &obj)); 5918 PetscCall(PetscObjectGetClassId(obj, &id)); 5919 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5920 5921 if (!fe) { 5922 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5923 /* An order k SEM disc has k-1 dofs on an edge */ 5924 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5925 *k = *k / *Nc + 1; 5926 } else { 5927 PetscInt dual_space_size, dim; 5928 PetscDualSpace dsp; 5929 5930 PetscCall(DMGetDimension(dm, &dim)); 5931 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5932 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5933 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5934 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5935 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5936 } 5937 PetscFunctionReturn(PETSC_SUCCESS); 5938 } 5939 5940 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5941 { 5942 PetscFunctionBeginHot; 5943 if (tensor) { 5944 *dof = PetscPowInt(k + 1, dim); 5945 } else { 5946 switch (dim) { 5947 case 1: 5948 *dof = k + 1; 5949 break; 5950 case 2: 5951 *dof = ((k + 1) * (k + 2)) / 2; 5952 break; 5953 case 3: 5954 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5955 break; 5956 default: 5957 *dof = 0; 5958 } 5959 } 5960 PetscFunctionReturn(PETSC_SUCCESS); 5961 } 5962 5963 /*@ 5964 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5965 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5966 section provided (or the section of the `DM`). 5967 5968 Input Parameters: 5969 + dm - The `DM` 5970 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5971 - section - The `PetscSection` to reorder, or `NULL` for the default section 5972 5973 Example: 5974 A typical interpolated single-quad mesh might order points as 5975 .vb 5976 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5977 5978 v4 -- e6 -- v3 5979 | | 5980 e7 c0 e8 5981 | | 5982 v1 -- e5 -- v2 5983 .ve 5984 5985 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5986 dofs in the order of points, e.g., 5987 .vb 5988 c0 -> [0,1,2,3] 5989 v1 -> [4] 5990 ... 5991 e5 -> [8, 9] 5992 .ve 5993 5994 which corresponds to the dofs 5995 .vb 5996 6 10 11 7 5997 13 2 3 15 5998 12 0 1 14 5999 4 8 9 5 6000 .ve 6001 6002 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 6003 .vb 6004 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 6005 .ve 6006 6007 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 6008 .vb 6009 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 6010 .ve 6011 6012 Level: developer 6013 6014 Notes: 6015 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 6016 degree of the basis. 6017 6018 This is required to run with libCEED. 6019 6020 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 6021 @*/ 6022 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 6023 { 6024 DMLabel label; 6025 PetscInt dim, depth = -1, eStart = -1, Nf; 6026 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 6027 6028 PetscFunctionBegin; 6029 PetscCall(DMGetDimension(dm, &dim)); 6030 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 6031 if (point < 0) { 6032 PetscInt sStart, sEnd; 6033 6034 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6035 point = sEnd - sStart ? sStart : point; 6036 } 6037 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6038 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6039 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6040 if (depth == 1) { 6041 eStart = point; 6042 } else if (depth == dim) { 6043 const PetscInt *cone; 6044 6045 PetscCall(DMPlexGetCone(dm, point, &cone)); 6046 if (dim == 2) eStart = cone[0]; 6047 else if (dim == 3) { 6048 const PetscInt *cone2; 6049 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6050 eStart = cone2[0]; 6051 } 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); 6052 } 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); 6053 6054 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6055 for (PetscInt d = 1; d <= dim; d++) { 6056 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6057 PetscInt *perm; 6058 6059 for (f = 0; f < Nf; ++f) { 6060 PetscInt dof; 6061 6062 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6063 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6064 if (!continuous && d < dim) continue; 6065 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6066 size += dof * Nc; 6067 } 6068 PetscCall(PetscMalloc1(size, &perm)); 6069 for (f = 0; f < Nf; ++f) { 6070 switch (d) { 6071 case 1: 6072 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6073 if (!continuous && d < dim) continue; 6074 /* 6075 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6076 We want [ vtx0; edge of length k-1; vtx1 ] 6077 */ 6078 if (continuous) { 6079 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6080 for (i = 0; i < k - 1; i++) 6081 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6082 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6083 foffset = offset; 6084 } else { 6085 PetscInt dof; 6086 6087 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6088 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6089 foffset = offset; 6090 } 6091 break; 6092 case 2: 6093 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6094 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6095 if (!continuous && d < dim) continue; 6096 /* The SEM order is 6097 6098 v_lb, {e_b}, v_rb, 6099 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6100 v_lt, reverse {e_t}, v_rt 6101 */ 6102 if (continuous) { 6103 const PetscInt of = 0; 6104 const PetscInt oeb = of + PetscSqr(k - 1); 6105 const PetscInt oer = oeb + (k - 1); 6106 const PetscInt oet = oer + (k - 1); 6107 const PetscInt oel = oet + (k - 1); 6108 const PetscInt ovlb = oel + (k - 1); 6109 const PetscInt ovrb = ovlb + 1; 6110 const PetscInt ovrt = ovrb + 1; 6111 const PetscInt ovlt = ovrt + 1; 6112 PetscInt o; 6113 6114 /* bottom */ 6115 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6116 for (o = oeb; o < oer; ++o) 6117 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6118 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6119 /* middle */ 6120 for (i = 0; i < k - 1; ++i) { 6121 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6122 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6123 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6124 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6125 } 6126 /* top */ 6127 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6128 for (o = oel - 1; o >= oet; --o) 6129 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6130 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6131 foffset = offset; 6132 } else { 6133 PetscInt dof; 6134 6135 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6136 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6137 foffset = offset; 6138 } 6139 break; 6140 case 3: 6141 /* The original hex closure is 6142 6143 {c, 6144 f_b, f_t, f_f, f_b, f_r, f_l, 6145 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6146 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6147 */ 6148 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6149 if (!continuous && d < dim) continue; 6150 /* The SEM order is 6151 Bottom Slice 6152 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6153 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6154 v_blb, {e_bb}, v_brb, 6155 6156 Middle Slice (j) 6157 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6158 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6159 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6160 6161 Top Slice 6162 v_tlf, {e_tf}, v_trf, 6163 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6164 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6165 */ 6166 if (continuous) { 6167 const PetscInt oc = 0; 6168 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6169 const PetscInt oft = ofb + PetscSqr(k - 1); 6170 const PetscInt off = oft + PetscSqr(k - 1); 6171 const PetscInt ofk = off + PetscSqr(k - 1); 6172 const PetscInt ofr = ofk + PetscSqr(k - 1); 6173 const PetscInt ofl = ofr + PetscSqr(k - 1); 6174 const PetscInt oebl = ofl + PetscSqr(k - 1); 6175 const PetscInt oebb = oebl + (k - 1); 6176 const PetscInt oebr = oebb + (k - 1); 6177 const PetscInt oebf = oebr + (k - 1); 6178 const PetscInt oetf = oebf + (k - 1); 6179 const PetscInt oetr = oetf + (k - 1); 6180 const PetscInt oetb = oetr + (k - 1); 6181 const PetscInt oetl = oetb + (k - 1); 6182 const PetscInt oerf = oetl + (k - 1); 6183 const PetscInt oelf = oerf + (k - 1); 6184 const PetscInt oelb = oelf + (k - 1); 6185 const PetscInt oerb = oelb + (k - 1); 6186 const PetscInt ovblf = oerb + (k - 1); 6187 const PetscInt ovblb = ovblf + 1; 6188 const PetscInt ovbrb = ovblb + 1; 6189 const PetscInt ovbrf = ovbrb + 1; 6190 const PetscInt ovtlf = ovbrf + 1; 6191 const PetscInt ovtrf = ovtlf + 1; 6192 const PetscInt ovtrb = ovtrf + 1; 6193 const PetscInt ovtlb = ovtrb + 1; 6194 PetscInt o, n; 6195 6196 /* Bottom Slice */ 6197 /* bottom */ 6198 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6199 for (o = oetf - 1; o >= oebf; --o) 6200 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6201 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6202 /* middle */ 6203 for (i = 0; i < k - 1; ++i) { 6204 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6205 for (n = 0; n < k - 1; ++n) { 6206 o = ofb + n * (k - 1) + i; 6207 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6208 } 6209 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6210 } 6211 /* top */ 6212 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6213 for (o = oebb; o < oebr; ++o) 6214 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6215 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6216 6217 /* Middle Slice */ 6218 for (j = 0; j < k - 1; ++j) { 6219 /* bottom */ 6220 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6221 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6222 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6223 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6224 /* middle */ 6225 for (i = 0; i < k - 1; ++i) { 6226 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6227 for (n = 0; n < k - 1; ++n) 6228 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6229 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6230 } 6231 /* top */ 6232 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6233 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6234 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6235 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6236 } 6237 6238 /* Top Slice */ 6239 /* bottom */ 6240 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6241 for (o = oetf; o < oetr; ++o) 6242 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6243 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6244 /* middle */ 6245 for (i = 0; i < k - 1; ++i) { 6246 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6247 for (n = 0; n < k - 1; ++n) 6248 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6249 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6250 } 6251 /* top */ 6252 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6253 for (o = oetl - 1; o >= oetb; --o) 6254 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6255 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6256 6257 foffset = offset; 6258 } else { 6259 PetscInt dof; 6260 6261 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6262 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6263 foffset = offset; 6264 } 6265 break; 6266 default: 6267 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6268 } 6269 } 6270 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6271 /* Check permutation */ 6272 { 6273 PetscInt *check; 6274 6275 PetscCall(PetscMalloc1(size, &check)); 6276 for (i = 0; i < size; ++i) { 6277 check[i] = -1; 6278 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6279 } 6280 for (i = 0; i < size; ++i) check[perm[i]] = i; 6281 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6282 PetscCall(PetscFree(check)); 6283 } 6284 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6285 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6286 PetscInt *loc_perm; 6287 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6288 for (PetscInt i = 0; i < size; i++) { 6289 loc_perm[i] = perm[i]; 6290 loc_perm[size + i] = size + perm[i]; 6291 } 6292 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6293 } 6294 } 6295 PetscFunctionReturn(PETSC_SUCCESS); 6296 } 6297 6298 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6299 { 6300 PetscDS prob; 6301 PetscInt depth, Nf, h; 6302 DMLabel label; 6303 6304 PetscFunctionBeginHot; 6305 PetscCall(DMGetDS(dm, &prob)); 6306 Nf = prob->Nf; 6307 label = dm->depthLabel; 6308 *dspace = NULL; 6309 if (field < Nf) { 6310 PetscObject disc = prob->disc[field]; 6311 6312 if (disc->classid == PETSCFE_CLASSID) { 6313 PetscDualSpace dsp; 6314 6315 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6316 PetscCall(DMLabelGetNumValues(label, &depth)); 6317 PetscCall(DMLabelGetValue(label, point, &h)); 6318 h = depth - 1 - h; 6319 if (h) { 6320 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6321 } else { 6322 *dspace = dsp; 6323 } 6324 } 6325 } 6326 PetscFunctionReturn(PETSC_SUCCESS); 6327 } 6328 6329 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6330 { 6331 PetscScalar *array; 6332 const PetscScalar *vArray; 6333 const PetscInt *cone, *coneO; 6334 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6335 6336 PetscFunctionBeginHot; 6337 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6338 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6339 PetscCall(DMPlexGetCone(dm, point, &cone)); 6340 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6341 if (!values || !*values) { 6342 if ((point >= pStart) && (point < pEnd)) { 6343 PetscInt dof; 6344 6345 PetscCall(PetscSectionGetDof(section, point, &dof)); 6346 size += dof; 6347 } 6348 for (p = 0; p < numPoints; ++p) { 6349 const PetscInt cp = cone[p]; 6350 PetscInt dof; 6351 6352 if ((cp < pStart) || (cp >= pEnd)) continue; 6353 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6354 size += dof; 6355 } 6356 if (!values) { 6357 if (csize) *csize = size; 6358 PetscFunctionReturn(PETSC_SUCCESS); 6359 } 6360 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6361 } else { 6362 array = *values; 6363 } 6364 size = 0; 6365 PetscCall(VecGetArrayRead(v, &vArray)); 6366 if ((point >= pStart) && (point < pEnd)) { 6367 PetscInt dof, off, d; 6368 const PetscScalar *varr; 6369 6370 PetscCall(PetscSectionGetDof(section, point, &dof)); 6371 PetscCall(PetscSectionGetOffset(section, point, &off)); 6372 varr = PetscSafePointerPlusOffset(vArray, off); 6373 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6374 size += dof; 6375 } 6376 for (p = 0; p < numPoints; ++p) { 6377 const PetscInt cp = cone[p]; 6378 PetscInt o = coneO[p]; 6379 PetscInt dof, off, d; 6380 const PetscScalar *varr; 6381 6382 if ((cp < pStart) || (cp >= pEnd)) continue; 6383 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6384 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6385 varr = PetscSafePointerPlusOffset(vArray, off); 6386 if (o >= 0) { 6387 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6388 } else { 6389 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6390 } 6391 size += dof; 6392 } 6393 PetscCall(VecRestoreArrayRead(v, &vArray)); 6394 if (!*values) { 6395 if (csize) *csize = size; 6396 *values = array; 6397 } else { 6398 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6399 *csize = size; 6400 } 6401 PetscFunctionReturn(PETSC_SUCCESS); 6402 } 6403 6404 /* Compress out points not in the section */ 6405 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6406 { 6407 const PetscInt np = *numPoints; 6408 PetscInt pStart, pEnd, p, q; 6409 6410 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6411 for (p = 0, q = 0; p < np; ++p) { 6412 const PetscInt r = points[p * 2]; 6413 if ((r >= pStart) && (r < pEnd)) { 6414 points[q * 2] = r; 6415 points[q * 2 + 1] = points[p * 2 + 1]; 6416 ++q; 6417 } 6418 } 6419 *numPoints = q; 6420 return PETSC_SUCCESS; 6421 } 6422 6423 /* Compressed closure does not apply closure permutation */ 6424 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6425 { 6426 const PetscInt *cla = NULL; 6427 PetscInt np, *pts = NULL; 6428 6429 PetscFunctionBeginHot; 6430 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6431 if (!ornt && *clPoints) { 6432 PetscInt dof, off; 6433 6434 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6435 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6436 PetscCall(ISGetIndices(*clPoints, &cla)); 6437 np = dof / 2; 6438 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6439 } else { 6440 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6441 PetscCall(CompressPoints_Private(section, &np, pts)); 6442 } 6443 *numPoints = np; 6444 *points = pts; 6445 *clp = cla; 6446 PetscFunctionReturn(PETSC_SUCCESS); 6447 } 6448 6449 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6450 { 6451 PetscFunctionBeginHot; 6452 if (!*clPoints) { 6453 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6454 } else { 6455 PetscCall(ISRestoreIndices(*clPoints, clp)); 6456 } 6457 *numPoints = 0; 6458 *points = NULL; 6459 *clSec = NULL; 6460 *clPoints = NULL; 6461 *clp = NULL; 6462 PetscFunctionReturn(PETSC_SUCCESS); 6463 } 6464 6465 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6466 { 6467 PetscInt offset = 0, p; 6468 const PetscInt **perms = NULL; 6469 const PetscScalar **flips = NULL; 6470 6471 PetscFunctionBeginHot; 6472 *size = 0; 6473 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6474 for (p = 0; p < numPoints; p++) { 6475 const PetscInt point = points[2 * p]; 6476 const PetscInt *perm = perms ? perms[p] : NULL; 6477 const PetscScalar *flip = flips ? flips[p] : NULL; 6478 PetscInt dof, off, d; 6479 const PetscScalar *varr; 6480 6481 PetscCall(PetscSectionGetDof(section, point, &dof)); 6482 PetscCall(PetscSectionGetOffset(section, point, &off)); 6483 varr = PetscSafePointerPlusOffset(vArray, off); 6484 if (clperm) { 6485 if (perm) { 6486 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6487 } else { 6488 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6489 } 6490 if (flip) { 6491 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6492 } 6493 } else { 6494 if (perm) { 6495 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6496 } else { 6497 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6498 } 6499 if (flip) { 6500 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6501 } 6502 } 6503 offset += dof; 6504 } 6505 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6506 *size = offset; 6507 PetscFunctionReturn(PETSC_SUCCESS); 6508 } 6509 6510 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[]) 6511 { 6512 PetscInt offset = 0, f; 6513 6514 PetscFunctionBeginHot; 6515 *size = 0; 6516 for (f = 0; f < numFields; ++f) { 6517 PetscInt p; 6518 const PetscInt **perms = NULL; 6519 const PetscScalar **flips = NULL; 6520 6521 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6522 for (p = 0; p < numPoints; p++) { 6523 const PetscInt point = points[2 * p]; 6524 PetscInt fdof, foff, b; 6525 const PetscScalar *varr; 6526 const PetscInt *perm = perms ? perms[p] : NULL; 6527 const PetscScalar *flip = flips ? flips[p] : NULL; 6528 6529 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6530 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6531 varr = &vArray[foff]; 6532 if (clperm) { 6533 if (perm) { 6534 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6535 } else { 6536 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6537 } 6538 if (flip) { 6539 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6540 } 6541 } else { 6542 if (perm) { 6543 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6544 } else { 6545 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6546 } 6547 if (flip) { 6548 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6549 } 6550 } 6551 offset += fdof; 6552 } 6553 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6554 } 6555 *size = offset; 6556 PetscFunctionReturn(PETSC_SUCCESS); 6557 } 6558 6559 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6560 { 6561 PetscSection clSection; 6562 IS clPoints; 6563 PetscInt *points = NULL; 6564 const PetscInt *clp, *perm = NULL; 6565 PetscInt depth, numFields, numPoints, asize; 6566 6567 PetscFunctionBeginHot; 6568 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6569 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6570 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6571 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6572 PetscCall(DMPlexGetDepth(dm, &depth)); 6573 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6574 if (depth == 1 && numFields < 2) { 6575 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6576 PetscFunctionReturn(PETSC_SUCCESS); 6577 } 6578 /* Get points */ 6579 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6580 /* Get sizes */ 6581 asize = 0; 6582 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6583 PetscInt dof; 6584 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6585 asize += dof; 6586 } 6587 if (values) { 6588 const PetscScalar *vArray; 6589 PetscInt size; 6590 6591 if (*values) { 6592 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); 6593 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6594 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6595 PetscCall(VecGetArrayRead(v, &vArray)); 6596 /* Get values */ 6597 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6598 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6599 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6600 /* Cleanup array */ 6601 PetscCall(VecRestoreArrayRead(v, &vArray)); 6602 } 6603 if (csize) *csize = asize; 6604 /* Cleanup points */ 6605 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6606 PetscFunctionReturn(PETSC_SUCCESS); 6607 } 6608 6609 /*@C 6610 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6611 6612 Not collective 6613 6614 Input Parameters: 6615 + dm - The `DM` 6616 . section - The section describing the layout in `v`, or `NULL` to use the default section 6617 . v - The local vector 6618 - point - The point in the `DM` 6619 6620 Input/Output Parameters: 6621 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6622 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6623 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6624 6625 Level: intermediate 6626 6627 Notes: 6628 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6629 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6630 assembly function, and a user may already have allocated storage for this operation. 6631 6632 A typical use could be 6633 .vb 6634 values = NULL; 6635 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6636 for (cl = 0; cl < clSize; ++cl) { 6637 <Compute on closure> 6638 } 6639 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6640 .ve 6641 or 6642 .vb 6643 PetscMalloc1(clMaxSize, &values); 6644 for (p = pStart; p < pEnd; ++p) { 6645 clSize = clMaxSize; 6646 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6647 for (cl = 0; cl < clSize; ++cl) { 6648 <Compute on closure> 6649 } 6650 } 6651 PetscFree(values); 6652 .ve 6653 6654 Fortran Notes: 6655 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6656 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6657 6658 `values` must be declared with 6659 .vb 6660 PetscScalar,dimension(:),pointer :: values 6661 .ve 6662 and it will be allocated internally by PETSc to hold the values returned 6663 6664 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6665 @*/ 6666 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6667 { 6668 PetscFunctionBeginHot; 6669 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6670 PetscFunctionReturn(PETSC_SUCCESS); 6671 } 6672 6673 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6674 { 6675 DMLabel depthLabel; 6676 PetscSection clSection; 6677 IS clPoints; 6678 PetscScalar *array; 6679 const PetscScalar *vArray; 6680 PetscInt *points = NULL; 6681 const PetscInt *clp, *perm = NULL; 6682 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6683 6684 PetscFunctionBeginHot; 6685 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6686 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6687 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6688 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6689 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6690 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6691 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6692 if (mdepth == 1 && numFields < 2) { 6693 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6694 PetscFunctionReturn(PETSC_SUCCESS); 6695 } 6696 /* Get points */ 6697 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6698 for (clsize = 0, p = 0; p < Np; p++) { 6699 PetscInt dof; 6700 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6701 clsize += dof; 6702 } 6703 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6704 /* Filter points */ 6705 for (p = 0; p < numPoints * 2; p += 2) { 6706 PetscInt dep; 6707 6708 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6709 if (dep != depth) continue; 6710 points[Np * 2 + 0] = points[p]; 6711 points[Np * 2 + 1] = points[p + 1]; 6712 ++Np; 6713 } 6714 /* Get array */ 6715 if (!values || !*values) { 6716 PetscInt asize = 0, dof; 6717 6718 for (p = 0; p < Np * 2; p += 2) { 6719 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6720 asize += dof; 6721 } 6722 if (!values) { 6723 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6724 if (csize) *csize = asize; 6725 PetscFunctionReturn(PETSC_SUCCESS); 6726 } 6727 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6728 } else { 6729 array = *values; 6730 } 6731 PetscCall(VecGetArrayRead(v, &vArray)); 6732 /* Get values */ 6733 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6734 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6735 /* Cleanup points */ 6736 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6737 /* Cleanup array */ 6738 PetscCall(VecRestoreArrayRead(v, &vArray)); 6739 if (!*values) { 6740 if (csize) *csize = size; 6741 *values = array; 6742 } else { 6743 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6744 *csize = size; 6745 } 6746 PetscFunctionReturn(PETSC_SUCCESS); 6747 } 6748 6749 /*@C 6750 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6751 6752 Not collective 6753 6754 Input Parameters: 6755 + dm - The `DM` 6756 . section - The section describing the layout in `v`, or `NULL` to use the default section 6757 . v - The local vector 6758 . point - The point in the `DM` 6759 . csize - The number of values in the closure, or `NULL` 6760 - values - The array of values 6761 6762 Level: intermediate 6763 6764 Note: 6765 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6766 6767 Fortran Note: 6768 The `csize` argument is present in the Fortran binding. Since the Fortran `values` array contains its length information this argument may not be needed. 6769 In that case one may pass `PETSC_NULL_INTEGER` for `csize`. 6770 6771 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6772 @*/ 6773 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6774 { 6775 PetscInt size = 0; 6776 6777 PetscFunctionBegin; 6778 /* Should work without recalculating size */ 6779 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6780 *values = NULL; 6781 PetscFunctionReturn(PETSC_SUCCESS); 6782 } 6783 6784 static inline void add(PetscScalar *x, PetscScalar y) 6785 { 6786 *x += y; 6787 } 6788 static inline void insert(PetscScalar *x, PetscScalar y) 6789 { 6790 *x = y; 6791 } 6792 6793 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[]) 6794 { 6795 PetscInt cdof; /* The number of constraints on this point */ 6796 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6797 PetscScalar *a; 6798 PetscInt off, cind = 0, k; 6799 6800 PetscFunctionBegin; 6801 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6802 PetscCall(PetscSectionGetOffset(section, point, &off)); 6803 a = &array[off]; 6804 if (!cdof || setBC) { 6805 if (clperm) { 6806 if (perm) { 6807 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6808 } else { 6809 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6810 } 6811 } else { 6812 if (perm) { 6813 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6814 } else { 6815 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6816 } 6817 } 6818 } else { 6819 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6820 if (clperm) { 6821 if (perm) { 6822 for (k = 0; k < dof; ++k) { 6823 if ((cind < cdof) && (k == cdofs[cind])) { 6824 ++cind; 6825 continue; 6826 } 6827 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6828 } 6829 } else { 6830 for (k = 0; k < dof; ++k) { 6831 if ((cind < cdof) && (k == cdofs[cind])) { 6832 ++cind; 6833 continue; 6834 } 6835 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6836 } 6837 } 6838 } else { 6839 if (perm) { 6840 for (k = 0; k < dof; ++k) { 6841 if ((cind < cdof) && (k == cdofs[cind])) { 6842 ++cind; 6843 continue; 6844 } 6845 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6846 } 6847 } else { 6848 for (k = 0; k < dof; ++k) { 6849 if ((cind < cdof) && (k == cdofs[cind])) { 6850 ++cind; 6851 continue; 6852 } 6853 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6854 } 6855 } 6856 } 6857 } 6858 PetscFunctionReturn(PETSC_SUCCESS); 6859 } 6860 6861 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[]) 6862 { 6863 PetscInt cdof; /* The number of constraints on this point */ 6864 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6865 PetscScalar *a; 6866 PetscInt off, cind = 0, k; 6867 6868 PetscFunctionBegin; 6869 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6870 PetscCall(PetscSectionGetOffset(section, point, &off)); 6871 a = &array[off]; 6872 if (cdof) { 6873 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6874 if (clperm) { 6875 if (perm) { 6876 for (k = 0; k < dof; ++k) { 6877 if ((cind < cdof) && (k == cdofs[cind])) { 6878 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6879 cind++; 6880 } 6881 } 6882 } else { 6883 for (k = 0; k < dof; ++k) { 6884 if ((cind < cdof) && (k == cdofs[cind])) { 6885 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6886 cind++; 6887 } 6888 } 6889 } 6890 } else { 6891 if (perm) { 6892 for (k = 0; k < dof; ++k) { 6893 if ((cind < cdof) && (k == cdofs[cind])) { 6894 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6895 cind++; 6896 } 6897 } 6898 } else { 6899 for (k = 0; k < dof; ++k) { 6900 if ((cind < cdof) && (k == cdofs[cind])) { 6901 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6902 cind++; 6903 } 6904 } 6905 } 6906 } 6907 } 6908 PetscFunctionReturn(PETSC_SUCCESS); 6909 } 6910 6911 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[]) 6912 { 6913 PetscScalar *a; 6914 PetscInt fdof, foff, fcdof, foffset = *offset; 6915 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6916 PetscInt cind = 0, b; 6917 6918 PetscFunctionBegin; 6919 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6920 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6921 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6922 a = &array[foff]; 6923 if (!fcdof || setBC) { 6924 if (clperm) { 6925 if (perm) { 6926 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6927 } else { 6928 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6929 } 6930 } else { 6931 if (perm) { 6932 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6933 } else { 6934 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6935 } 6936 } 6937 } else { 6938 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6939 if (clperm) { 6940 if (perm) { 6941 for (b = 0; b < fdof; b++) { 6942 if ((cind < fcdof) && (b == fcdofs[cind])) { 6943 ++cind; 6944 continue; 6945 } 6946 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6947 } 6948 } else { 6949 for (b = 0; b < fdof; b++) { 6950 if ((cind < fcdof) && (b == fcdofs[cind])) { 6951 ++cind; 6952 continue; 6953 } 6954 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6955 } 6956 } 6957 } else { 6958 if (perm) { 6959 for (b = 0; b < fdof; b++) { 6960 if ((cind < fcdof) && (b == fcdofs[cind])) { 6961 ++cind; 6962 continue; 6963 } 6964 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6965 } 6966 } else { 6967 for (b = 0; b < fdof; b++) { 6968 if ((cind < fcdof) && (b == fcdofs[cind])) { 6969 ++cind; 6970 continue; 6971 } 6972 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6973 } 6974 } 6975 } 6976 } 6977 *offset += fdof; 6978 PetscFunctionReturn(PETSC_SUCCESS); 6979 } 6980 6981 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[]) 6982 { 6983 PetscScalar *a; 6984 PetscInt fdof, foff, fcdof, foffset = *offset; 6985 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6986 PetscInt Nc, cind = 0, ncind = 0, b; 6987 PetscBool ncSet, fcSet; 6988 6989 PetscFunctionBegin; 6990 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6991 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6992 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6993 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6994 a = &array[foff]; 6995 if (fcdof) { 6996 /* We just override fcdof and fcdofs with Ncc and comps */ 6997 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6998 if (clperm) { 6999 if (perm) { 7000 if (comps) { 7001 for (b = 0; b < fdof; b++) { 7002 ncSet = fcSet = PETSC_FALSE; 7003 if (b % Nc == comps[ncind]) { 7004 ncind = (ncind + 1) % Ncc; 7005 ncSet = PETSC_TRUE; 7006 } 7007 if ((cind < fcdof) && (b == fcdofs[cind])) { 7008 ++cind; 7009 fcSet = PETSC_TRUE; 7010 } 7011 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7012 } 7013 } else { 7014 for (b = 0; b < fdof; b++) { 7015 if ((cind < fcdof) && (b == fcdofs[cind])) { 7016 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 7017 ++cind; 7018 } 7019 } 7020 } 7021 } else { 7022 if (comps) { 7023 for (b = 0; b < fdof; b++) { 7024 ncSet = fcSet = PETSC_FALSE; 7025 if (b % Nc == comps[ncind]) { 7026 ncind = (ncind + 1) % Ncc; 7027 ncSet = PETSC_TRUE; 7028 } 7029 if ((cind < fcdof) && (b == fcdofs[cind])) { 7030 ++cind; 7031 fcSet = PETSC_TRUE; 7032 } 7033 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7034 } 7035 } else { 7036 for (b = 0; b < fdof; b++) { 7037 if ((cind < fcdof) && (b == fcdofs[cind])) { 7038 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7039 ++cind; 7040 } 7041 } 7042 } 7043 } 7044 } else { 7045 if (perm) { 7046 if (comps) { 7047 for (b = 0; b < fdof; b++) { 7048 ncSet = fcSet = PETSC_FALSE; 7049 if (b % Nc == comps[ncind]) { 7050 ncind = (ncind + 1) % Ncc; 7051 ncSet = PETSC_TRUE; 7052 } 7053 if ((cind < fcdof) && (b == fcdofs[cind])) { 7054 ++cind; 7055 fcSet = PETSC_TRUE; 7056 } 7057 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7058 } 7059 } else { 7060 for (b = 0; b < fdof; b++) { 7061 if ((cind < fcdof) && (b == fcdofs[cind])) { 7062 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7063 ++cind; 7064 } 7065 } 7066 } 7067 } else { 7068 if (comps) { 7069 for (b = 0; b < fdof; b++) { 7070 ncSet = fcSet = PETSC_FALSE; 7071 if (b % Nc == comps[ncind]) { 7072 ncind = (ncind + 1) % Ncc; 7073 ncSet = PETSC_TRUE; 7074 } 7075 if ((cind < fcdof) && (b == fcdofs[cind])) { 7076 ++cind; 7077 fcSet = PETSC_TRUE; 7078 } 7079 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7080 } 7081 } else { 7082 for (b = 0; b < fdof; b++) { 7083 if ((cind < fcdof) && (b == fcdofs[cind])) { 7084 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7085 ++cind; 7086 } 7087 } 7088 } 7089 } 7090 } 7091 } 7092 *offset += fdof; 7093 PetscFunctionReturn(PETSC_SUCCESS); 7094 } 7095 7096 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7097 { 7098 PetscScalar *array; 7099 const PetscInt *cone, *coneO; 7100 PetscInt pStart, pEnd, p, numPoints, off, dof; 7101 7102 PetscFunctionBeginHot; 7103 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7104 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7105 PetscCall(DMPlexGetCone(dm, point, &cone)); 7106 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7107 PetscCall(VecGetArray(v, &array)); 7108 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7109 const PetscInt cp = !p ? point : cone[p - 1]; 7110 const PetscInt o = !p ? 0 : coneO[p - 1]; 7111 7112 if ((cp < pStart) || (cp >= pEnd)) { 7113 dof = 0; 7114 continue; 7115 } 7116 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7117 /* ADD_VALUES */ 7118 { 7119 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7120 PetscScalar *a; 7121 PetscInt cdof, coff, cind = 0, k; 7122 7123 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7124 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7125 a = &array[coff]; 7126 if (!cdof) { 7127 if (o >= 0) { 7128 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7129 } else { 7130 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7131 } 7132 } else { 7133 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7134 if (o >= 0) { 7135 for (k = 0; k < dof; ++k) { 7136 if ((cind < cdof) && (k == cdofs[cind])) { 7137 ++cind; 7138 continue; 7139 } 7140 a[k] += values[off + k]; 7141 } 7142 } else { 7143 for (k = 0; k < dof; ++k) { 7144 if ((cind < cdof) && (k == cdofs[cind])) { 7145 ++cind; 7146 continue; 7147 } 7148 a[k] += values[off + dof - k - 1]; 7149 } 7150 } 7151 } 7152 } 7153 } 7154 PetscCall(VecRestoreArray(v, &array)); 7155 PetscFunctionReturn(PETSC_SUCCESS); 7156 } 7157 7158 /*@C 7159 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7160 7161 Not collective 7162 7163 Input Parameters: 7164 + dm - The `DM` 7165 . section - The section describing the layout in `v`, or `NULL` to use the default section 7166 . v - The local vector 7167 . point - The point in the `DM` 7168 . values - The array of values 7169 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7170 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7171 7172 Level: intermediate 7173 7174 Note: 7175 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7176 7177 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7178 @*/ 7179 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7180 { 7181 PetscSection clSection; 7182 IS clPoints; 7183 PetscScalar *array; 7184 PetscInt *points = NULL; 7185 const PetscInt *clp, *clperm = NULL; 7186 PetscInt depth, numFields, numPoints, p, clsize; 7187 7188 PetscFunctionBeginHot; 7189 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7190 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7191 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7192 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7193 PetscCall(DMPlexGetDepth(dm, &depth)); 7194 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7195 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7196 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7197 PetscFunctionReturn(PETSC_SUCCESS); 7198 } 7199 /* Get points */ 7200 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7201 for (clsize = 0, p = 0; p < numPoints; p++) { 7202 PetscInt dof; 7203 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7204 clsize += dof; 7205 } 7206 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7207 /* Get array */ 7208 PetscCall(VecGetArray(v, &array)); 7209 /* Get values */ 7210 if (numFields > 0) { 7211 PetscInt offset = 0, f; 7212 for (f = 0; f < numFields; ++f) { 7213 const PetscInt **perms = NULL; 7214 const PetscScalar **flips = NULL; 7215 7216 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7217 switch (mode) { 7218 case INSERT_VALUES: 7219 for (p = 0; p < numPoints; p++) { 7220 const PetscInt point = points[2 * p]; 7221 const PetscInt *perm = perms ? perms[p] : NULL; 7222 const PetscScalar *flip = flips ? flips[p] : NULL; 7223 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7224 } 7225 break; 7226 case INSERT_ALL_VALUES: 7227 for (p = 0; p < numPoints; p++) { 7228 const PetscInt point = points[2 * p]; 7229 const PetscInt *perm = perms ? perms[p] : NULL; 7230 const PetscScalar *flip = flips ? flips[p] : NULL; 7231 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7232 } 7233 break; 7234 case INSERT_BC_VALUES: 7235 for (p = 0; p < numPoints; p++) { 7236 const PetscInt point = points[2 * p]; 7237 const PetscInt *perm = perms ? perms[p] : NULL; 7238 const PetscScalar *flip = flips ? flips[p] : NULL; 7239 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7240 } 7241 break; 7242 case ADD_VALUES: 7243 for (p = 0; p < numPoints; p++) { 7244 const PetscInt point = points[2 * p]; 7245 const PetscInt *perm = perms ? perms[p] : NULL; 7246 const PetscScalar *flip = flips ? flips[p] : NULL; 7247 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7248 } 7249 break; 7250 case ADD_ALL_VALUES: 7251 for (p = 0; p < numPoints; p++) { 7252 const PetscInt point = points[2 * p]; 7253 const PetscInt *perm = perms ? perms[p] : NULL; 7254 const PetscScalar *flip = flips ? flips[p] : NULL; 7255 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7256 } 7257 break; 7258 case ADD_BC_VALUES: 7259 for (p = 0; p < numPoints; p++) { 7260 const PetscInt point = points[2 * p]; 7261 const PetscInt *perm = perms ? perms[p] : NULL; 7262 const PetscScalar *flip = flips ? flips[p] : NULL; 7263 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7264 } 7265 break; 7266 default: 7267 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7268 } 7269 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7270 } 7271 } else { 7272 PetscInt dof, off; 7273 const PetscInt **perms = NULL; 7274 const PetscScalar **flips = NULL; 7275 7276 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7277 switch (mode) { 7278 case INSERT_VALUES: 7279 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7280 const PetscInt point = points[2 * p]; 7281 const PetscInt *perm = perms ? perms[p] : NULL; 7282 const PetscScalar *flip = flips ? flips[p] : NULL; 7283 PetscCall(PetscSectionGetDof(section, point, &dof)); 7284 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7285 } 7286 break; 7287 case INSERT_ALL_VALUES: 7288 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7289 const PetscInt point = points[2 * p]; 7290 const PetscInt *perm = perms ? perms[p] : NULL; 7291 const PetscScalar *flip = flips ? flips[p] : NULL; 7292 PetscCall(PetscSectionGetDof(section, point, &dof)); 7293 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7294 } 7295 break; 7296 case INSERT_BC_VALUES: 7297 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7298 const PetscInt point = points[2 * p]; 7299 const PetscInt *perm = perms ? perms[p] : NULL; 7300 const PetscScalar *flip = flips ? flips[p] : NULL; 7301 PetscCall(PetscSectionGetDof(section, point, &dof)); 7302 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7303 } 7304 break; 7305 case ADD_VALUES: 7306 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7307 const PetscInt point = points[2 * p]; 7308 const PetscInt *perm = perms ? perms[p] : NULL; 7309 const PetscScalar *flip = flips ? flips[p] : NULL; 7310 PetscCall(PetscSectionGetDof(section, point, &dof)); 7311 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7312 } 7313 break; 7314 case ADD_ALL_VALUES: 7315 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7316 const PetscInt point = points[2 * p]; 7317 const PetscInt *perm = perms ? perms[p] : NULL; 7318 const PetscScalar *flip = flips ? flips[p] : NULL; 7319 PetscCall(PetscSectionGetDof(section, point, &dof)); 7320 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7321 } 7322 break; 7323 case ADD_BC_VALUES: 7324 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7325 const PetscInt point = points[2 * p]; 7326 const PetscInt *perm = perms ? perms[p] : NULL; 7327 const PetscScalar *flip = flips ? flips[p] : NULL; 7328 PetscCall(PetscSectionGetDof(section, point, &dof)); 7329 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7330 } 7331 break; 7332 default: 7333 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7334 } 7335 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7336 } 7337 /* Cleanup points */ 7338 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7339 /* Cleanup array */ 7340 PetscCall(VecRestoreArray(v, &array)); 7341 PetscFunctionReturn(PETSC_SUCCESS); 7342 } 7343 7344 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7345 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7346 { 7347 PetscFunctionBegin; 7348 *contains = PETSC_TRUE; 7349 if (label) { 7350 PetscInt fdof; 7351 7352 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7353 if (!*contains) { 7354 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7355 *offset += fdof; 7356 PetscFunctionReturn(PETSC_SUCCESS); 7357 } 7358 } 7359 PetscFunctionReturn(PETSC_SUCCESS); 7360 } 7361 7362 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7363 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) 7364 { 7365 PetscSection clSection; 7366 IS clPoints; 7367 PetscScalar *array; 7368 PetscInt *points = NULL; 7369 const PetscInt *clp; 7370 PetscInt numFields, numPoints, p; 7371 PetscInt offset = 0, f; 7372 7373 PetscFunctionBeginHot; 7374 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7375 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7376 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7377 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7378 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7379 /* Get points */ 7380 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7381 /* Get array */ 7382 PetscCall(VecGetArray(v, &array)); 7383 /* Get values */ 7384 for (f = 0; f < numFields; ++f) { 7385 const PetscInt **perms = NULL; 7386 const PetscScalar **flips = NULL; 7387 PetscBool contains; 7388 7389 if (!fieldActive[f]) { 7390 for (p = 0; p < numPoints * 2; p += 2) { 7391 PetscInt fdof; 7392 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7393 offset += fdof; 7394 } 7395 continue; 7396 } 7397 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7398 switch (mode) { 7399 case INSERT_VALUES: 7400 for (p = 0; p < numPoints; p++) { 7401 const PetscInt point = points[2 * p]; 7402 const PetscInt *perm = perms ? perms[p] : NULL; 7403 const PetscScalar *flip = flips ? flips[p] : NULL; 7404 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7405 if (!contains) continue; 7406 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7407 } 7408 break; 7409 case INSERT_ALL_VALUES: 7410 for (p = 0; p < numPoints; p++) { 7411 const PetscInt point = points[2 * p]; 7412 const PetscInt *perm = perms ? perms[p] : NULL; 7413 const PetscScalar *flip = flips ? flips[p] : NULL; 7414 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7415 if (!contains) continue; 7416 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7417 } 7418 break; 7419 case INSERT_BC_VALUES: 7420 for (p = 0; p < numPoints; p++) { 7421 const PetscInt point = points[2 * p]; 7422 const PetscInt *perm = perms ? perms[p] : NULL; 7423 const PetscScalar *flip = flips ? flips[p] : NULL; 7424 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7425 if (!contains) continue; 7426 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7427 } 7428 break; 7429 case ADD_VALUES: 7430 for (p = 0; p < numPoints; p++) { 7431 const PetscInt point = points[2 * p]; 7432 const PetscInt *perm = perms ? perms[p] : NULL; 7433 const PetscScalar *flip = flips ? flips[p] : NULL; 7434 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7435 if (!contains) continue; 7436 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7437 } 7438 break; 7439 case ADD_ALL_VALUES: 7440 for (p = 0; p < numPoints; p++) { 7441 const PetscInt point = points[2 * p]; 7442 const PetscInt *perm = perms ? perms[p] : NULL; 7443 const PetscScalar *flip = flips ? flips[p] : NULL; 7444 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7445 if (!contains) continue; 7446 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7447 } 7448 break; 7449 default: 7450 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7451 } 7452 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7453 } 7454 /* Cleanup points */ 7455 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7456 /* Cleanup array */ 7457 PetscCall(VecRestoreArray(v, &array)); 7458 PetscFunctionReturn(PETSC_SUCCESS); 7459 } 7460 7461 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7462 { 7463 PetscMPIInt rank; 7464 PetscInt i, j; 7465 7466 PetscFunctionBegin; 7467 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7468 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7469 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7470 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7471 numCIndices = numCIndices ? numCIndices : numRIndices; 7472 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7473 for (i = 0; i < numRIndices; i++) { 7474 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7475 for (j = 0; j < numCIndices; j++) { 7476 #if defined(PETSC_USE_COMPLEX) 7477 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7478 #else 7479 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7480 #endif 7481 } 7482 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7483 } 7484 PetscFunctionReturn(PETSC_SUCCESS); 7485 } 7486 7487 /* 7488 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7489 7490 Input Parameters: 7491 + section - The section for this data layout 7492 . islocal - Is the section (and thus indices being requested) local or global? 7493 . point - The point contributing dofs with these indices 7494 . off - The global offset of this point 7495 . loff - The local offset of each field 7496 . setBC - The flag determining whether to include indices of boundary values 7497 . perm - A permutation of the dofs on this point, or NULL 7498 - indperm - A permutation of the entire indices array, or NULL 7499 7500 Output Parameter: 7501 . indices - Indices for dofs on this point 7502 7503 Level: developer 7504 7505 Note: The indices could be local or global, depending on the value of 'off'. 7506 */ 7507 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7508 { 7509 PetscInt dof; /* The number of unknowns on this point */ 7510 PetscInt cdof; /* The number of constraints on this point */ 7511 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7512 PetscInt cind = 0, k; 7513 7514 PetscFunctionBegin; 7515 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7516 PetscCall(PetscSectionGetDof(section, point, &dof)); 7517 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7518 if (!cdof || setBC) { 7519 for (k = 0; k < dof; ++k) { 7520 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7521 const PetscInt ind = indperm ? indperm[preind] : preind; 7522 7523 indices[ind] = off + k; 7524 } 7525 } else { 7526 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7527 for (k = 0; k < dof; ++k) { 7528 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7529 const PetscInt ind = indperm ? indperm[preind] : preind; 7530 7531 if ((cind < cdof) && (k == cdofs[cind])) { 7532 /* Insert check for returning constrained indices */ 7533 indices[ind] = -(off + k + 1); 7534 ++cind; 7535 } else { 7536 indices[ind] = off + k - (islocal ? 0 : cind); 7537 } 7538 } 7539 } 7540 *loff += dof; 7541 PetscFunctionReturn(PETSC_SUCCESS); 7542 } 7543 7544 /* 7545 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7546 7547 Input Parameters: 7548 + section - a section (global or local) 7549 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7550 . point - point within section 7551 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7552 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7553 . setBC - identify constrained (boundary condition) points via involution. 7554 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7555 . permsoff - offset 7556 - indperm - index permutation 7557 7558 Output Parameter: 7559 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7560 . indices - array to hold indices (as defined by section) of each dof associated with point 7561 7562 Notes: 7563 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7564 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7565 in the local vector. 7566 7567 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7568 significant). It is invalid to call with a global section and setBC=true. 7569 7570 Developer Note: 7571 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7572 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7573 offset could be obtained from the section instead of passing it explicitly as we do now. 7574 7575 Example: 7576 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7577 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7578 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7579 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. 7580 7581 Level: developer 7582 */ 7583 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[]) 7584 { 7585 PetscInt numFields, foff, f; 7586 7587 PetscFunctionBegin; 7588 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7589 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7590 for (f = 0, foff = 0; f < numFields; ++f) { 7591 PetscInt fdof, cfdof; 7592 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7593 PetscInt cind = 0, b; 7594 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7595 7596 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7597 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7598 if (!cfdof || setBC) { 7599 for (b = 0; b < fdof; ++b) { 7600 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7601 const PetscInt ind = indperm ? indperm[preind] : preind; 7602 7603 indices[ind] = off + foff + b; 7604 } 7605 } else { 7606 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7607 for (b = 0; b < fdof; ++b) { 7608 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7609 const PetscInt ind = indperm ? indperm[preind] : preind; 7610 7611 if ((cind < cfdof) && (b == fcdofs[cind])) { 7612 indices[ind] = -(off + foff + b + 1); 7613 ++cind; 7614 } else { 7615 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7616 } 7617 } 7618 } 7619 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7620 foffs[f] += fdof; 7621 } 7622 PetscFunctionReturn(PETSC_SUCCESS); 7623 } 7624 7625 /* 7626 This version believes the globalSection offsets for each field, rather than just the point offset 7627 7628 . foffs - The offset into 'indices' for each field, since it is segregated by field 7629 7630 Notes: 7631 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7632 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7633 */ 7634 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7635 { 7636 PetscInt numFields, foff, f; 7637 7638 PetscFunctionBegin; 7639 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7640 for (f = 0; f < numFields; ++f) { 7641 PetscInt fdof, cfdof; 7642 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7643 PetscInt cind = 0, b; 7644 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7645 7646 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7647 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7648 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7649 if (!cfdof) { 7650 for (b = 0; b < fdof; ++b) { 7651 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7652 const PetscInt ind = indperm ? indperm[preind] : preind; 7653 7654 indices[ind] = foff + b; 7655 } 7656 } else { 7657 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7658 for (b = 0; b < fdof; ++b) { 7659 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7660 const PetscInt ind = indperm ? indperm[preind] : preind; 7661 7662 if ((cind < cfdof) && (b == fcdofs[cind])) { 7663 indices[ind] = -(foff + b + 1); 7664 ++cind; 7665 } else { 7666 indices[ind] = foff + b - cind; 7667 } 7668 } 7669 } 7670 foffs[f] += fdof; 7671 } 7672 PetscFunctionReturn(PETSC_SUCCESS); 7673 } 7674 7675 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7676 { 7677 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7678 7679 PetscFunctionBegin; 7680 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7681 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7682 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7683 for (PetscInt p = 0; p < nPoints; p++) { 7684 PetscInt b = pnts[2 * p]; 7685 PetscInt bSecDof = 0, bOff; 7686 PetscInt cSecDof = 0; 7687 PetscSection indices_section; 7688 7689 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7690 if (!bSecDof) continue; 7691 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7692 indices_section = cSecDof > 0 ? cSec : section; 7693 if (numFields) { 7694 PetscInt fStart[32], fEnd[32]; 7695 7696 fStart[0] = 0; 7697 fEnd[0] = 0; 7698 for (PetscInt f = 0; f < numFields; f++) { 7699 PetscInt fDof = 0; 7700 7701 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7702 fStart[f + 1] = fStart[f] + fDof; 7703 fEnd[f + 1] = fStart[f + 1]; 7704 } 7705 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7706 // only apply permutations on one side 7707 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7708 for (PetscInt f = 0; f < numFields; f++) { 7709 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7710 } 7711 } else { 7712 PetscInt bEnd = 0; 7713 7714 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7715 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7716 7717 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7718 } 7719 } 7720 PetscFunctionReturn(PETSC_SUCCESS); 7721 } 7722 7723 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[]) 7724 { 7725 Mat cMat; 7726 PetscSection aSec, cSec; 7727 IS aIS; 7728 PetscInt aStart = -1, aEnd = -1; 7729 PetscInt sStart = -1, sEnd = -1; 7730 PetscInt cStart = -1, cEnd = -1; 7731 const PetscInt *anchors; 7732 PetscInt numFields, p; 7733 PetscInt newNumPoints = 0, newNumIndices = 0; 7734 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7735 PetscInt oldOffsets[32]; 7736 PetscInt newOffsets[32]; 7737 PetscInt oldOffsetsCopy[32]; 7738 PetscInt newOffsetsCopy[32]; 7739 PetscScalar *modMat = NULL; 7740 PetscBool anyConstrained = PETSC_FALSE; 7741 7742 PetscFunctionBegin; 7743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7744 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7745 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7746 7747 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7748 /* if there are point-to-point constraints */ 7749 if (aSec) { 7750 PetscCall(PetscArrayzero(newOffsets, 32)); 7751 PetscCall(PetscArrayzero(oldOffsets, 32)); 7752 PetscCall(ISGetIndices(aIS, &anchors)); 7753 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7754 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7755 /* figure out how many points are going to be in the new element matrix 7756 * (we allow double counting, because it's all just going to be summed 7757 * into the global matrix anyway) */ 7758 for (p = 0; p < 2 * numPoints; p += 2) { 7759 PetscInt b = points[p]; 7760 PetscInt bDof = 0, bSecDof = 0; 7761 7762 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7763 if (!bSecDof) continue; 7764 7765 for (PetscInt f = 0; f < numFields; f++) { 7766 PetscInt fDof = 0; 7767 7768 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7769 oldOffsets[f + 1] += fDof; 7770 } 7771 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7772 if (bDof) { 7773 /* this point is constrained */ 7774 /* it is going to be replaced by its anchors */ 7775 PetscInt bOff, q; 7776 7777 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7778 for (q = 0; q < bDof; q++) { 7779 PetscInt a = anchors[bOff + q]; 7780 PetscInt aDof = 0; 7781 7782 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7783 if (aDof) { 7784 anyConstrained = PETSC_TRUE; 7785 newNumPoints += 1; 7786 } 7787 newNumIndices += aDof; 7788 for (PetscInt f = 0; f < numFields; ++f) { 7789 PetscInt fDof = 0; 7790 7791 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7792 newOffsets[f + 1] += fDof; 7793 } 7794 } 7795 } else { 7796 /* this point is not constrained */ 7797 newNumPoints++; 7798 newNumIndices += bSecDof; 7799 for (PetscInt f = 0; f < numFields; ++f) { 7800 PetscInt fDof; 7801 7802 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7803 newOffsets[f + 1] += fDof; 7804 } 7805 } 7806 } 7807 } 7808 if (!anyConstrained) { 7809 if (outNumPoints) *outNumPoints = 0; 7810 if (outNumIndices) *outNumIndices = 0; 7811 if (outPoints) *outPoints = NULL; 7812 if (outMat) *outMat = NULL; 7813 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7814 PetscFunctionReturn(PETSC_SUCCESS); 7815 } 7816 7817 if (outNumPoints) *outNumPoints = newNumPoints; 7818 if (outNumIndices) *outNumIndices = newNumIndices; 7819 7820 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7821 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7822 7823 if (!outPoints && !outMat) { 7824 if (offsets) { 7825 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7826 } 7827 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7828 PetscFunctionReturn(PETSC_SUCCESS); 7829 } 7830 7831 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7832 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7833 7834 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7835 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7836 7837 /* output arrays */ 7838 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7839 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7840 7841 // get the new Points 7842 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7843 PetscInt b = points[2 * p]; 7844 PetscInt bDof = 0, bSecDof = 0, bOff; 7845 7846 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7847 if (!bSecDof) continue; 7848 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7849 if (bDof) { 7850 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7851 for (PetscInt q = 0; q < bDof; q++) { 7852 PetscInt a = anchors[bOff + q], aDof = 0; 7853 7854 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7855 if (aDof) { 7856 newPoints[2 * newP] = a; 7857 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7858 newP++; 7859 } 7860 } 7861 } else { 7862 newPoints[2 * newP] = b; 7863 newPoints[2 * newP + 1] = points[2 * p + 1]; 7864 newP++; 7865 } 7866 } 7867 7868 if (outMat) { 7869 PetscScalar *tmpMat; 7870 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7871 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7872 7873 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7874 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7875 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7876 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7877 7878 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7879 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7880 7881 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7882 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7883 7884 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7885 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7886 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7887 // for each field, insert the anchor modification into modMat 7888 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7889 PetscInt fStart = oldOffsets[f]; 7890 PetscInt fNewStart = newOffsets[f]; 7891 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7892 PetscInt b = points[2 * p]; 7893 PetscInt bDof = 0, bSecDof = 0, bOff; 7894 7895 if (b >= sStart && b < sEnd) { 7896 if (numFields) { 7897 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7898 } else { 7899 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7900 } 7901 } 7902 if (!bSecDof) continue; 7903 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7904 if (bDof) { 7905 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7906 for (PetscInt q = 0; q < bDof; q++, newP++) { 7907 PetscInt a = anchors[bOff + q], aDof = 0; 7908 7909 if (a >= sStart && a < sEnd) { 7910 if (numFields) { 7911 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7912 } else { 7913 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7914 } 7915 } 7916 if (aDof) { 7917 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7918 for (PetscInt d = 0; d < bSecDof; d++) { 7919 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7920 } 7921 } 7922 oNew += aDof; 7923 } 7924 } else { 7925 // Insert the identity matrix in this block 7926 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7927 oNew += bSecDof; 7928 newP++; 7929 } 7930 o += bSecDof; 7931 } 7932 } 7933 7934 *outMat = modMat; 7935 7936 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7937 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7938 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7939 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7940 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7941 } 7942 PetscCall(ISRestoreIndices(aIS, &anchors)); 7943 7944 /* output */ 7945 if (outPoints) { 7946 *outPoints = newPoints; 7947 } else { 7948 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7949 } 7950 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7951 PetscFunctionReturn(PETSC_SUCCESS); 7952 } 7953 7954 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) 7955 { 7956 PetscScalar *modMat = NULL; 7957 PetscInt newNumIndices = -1; 7958 7959 PetscFunctionBegin; 7960 /* 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. 7961 modMat is that matrix C */ 7962 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7963 if (outNumIndices) *outNumIndices = newNumIndices; 7964 if (modMat) { 7965 const PetscScalar *newValues = values; 7966 7967 if (multiplyRight) { 7968 PetscScalar *newNewValues = NULL; 7969 PetscBLASInt M, N, K; 7970 PetscScalar a = 1.0, b = 0.0; 7971 7972 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); 7973 7974 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7975 PetscCall(PetscBLASIntCast(numRows, &N)); 7976 PetscCall(PetscBLASIntCast(numIndices, &K)); 7977 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7978 // row-major to column-major conversion, right multiplication becomes left multiplication 7979 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7980 numCols = newNumIndices; 7981 newValues = newNewValues; 7982 } 7983 7984 if (multiplyLeft) { 7985 PetscScalar *newNewValues = NULL; 7986 PetscBLASInt M, N, K; 7987 PetscScalar a = 1.0, b = 0.0; 7988 7989 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); 7990 7991 PetscCall(PetscBLASIntCast(numCols, &M)); 7992 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7993 PetscCall(PetscBLASIntCast(numIndices, &K)); 7994 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7995 // row-major to column-major conversion, left multiplication becomes right multiplication 7996 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7997 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7998 newValues = newNewValues; 7999 } 8000 *outValues = (PetscScalar *)newValues; 8001 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 8002 } 8003 PetscFunctionReturn(PETSC_SUCCESS); 8004 } 8005 8006 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) 8007 { 8008 PetscFunctionBegin; 8009 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 8010 PetscFunctionReturn(PETSC_SUCCESS); 8011 } 8012 8013 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 8014 { 8015 /* Closure ordering */ 8016 PetscSection clSection; 8017 IS clPoints; 8018 const PetscInt *clp; 8019 PetscInt *points; 8020 PetscInt Ncl, Ni = 0; 8021 8022 PetscFunctionBeginHot; 8023 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8024 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 8025 PetscInt dof; 8026 8027 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8028 Ni += dof; 8029 } 8030 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8031 *closureSize = Ni; 8032 PetscFunctionReturn(PETSC_SUCCESS); 8033 } 8034 8035 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) 8036 { 8037 /* Closure ordering */ 8038 PetscSection clSection; 8039 IS clPoints; 8040 const PetscInt *clp; 8041 PetscInt *points; 8042 const PetscInt *clperm = NULL; 8043 /* Dof permutation and sign flips */ 8044 const PetscInt **perms[32] = {NULL}; 8045 const PetscScalar **flips[32] = {NULL}; 8046 PetscScalar *valCopy = NULL; 8047 /* Hanging node constraints */ 8048 PetscInt *pointsC = NULL; 8049 PetscScalar *valuesC = NULL; 8050 PetscInt NclC, NiC; 8051 8052 PetscInt *idx; 8053 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8054 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8055 PetscInt idxStart, idxEnd; 8056 PetscInt nRows, nCols; 8057 8058 PetscFunctionBeginHot; 8059 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8060 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8061 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8062 PetscAssertPointer(numRows, 6); 8063 PetscAssertPointer(numCols, 7); 8064 if (indices) PetscAssertPointer(indices, 8); 8065 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8066 if (values) PetscAssertPointer(values, 10); 8067 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8068 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8069 PetscCall(PetscArrayzero(offsets, 32)); 8070 /* 1) Get points in closure */ 8071 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8072 if (useClPerm) { 8073 PetscInt depth, clsize; 8074 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8075 for (clsize = 0, p = 0; p < Ncl; p++) { 8076 PetscInt dof; 8077 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8078 clsize += dof; 8079 } 8080 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8081 } 8082 /* 2) Get number of indices on these points and field offsets from section */ 8083 for (p = 0; p < Ncl * 2; p += 2) { 8084 PetscInt dof, fdof; 8085 8086 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8087 for (f = 0; f < Nf; ++f) { 8088 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8089 offsets[f + 1] += fdof; 8090 } 8091 Ni += dof; 8092 } 8093 if (*numRows == -1) *numRows = Ni; 8094 if (*numCols == -1) *numCols = Ni; 8095 nRows = *numRows; 8096 nCols = *numCols; 8097 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8098 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8099 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8100 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8101 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8102 for (f = 0; f < PetscMax(1, Nf); ++f) { 8103 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8104 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8105 /* may need to apply sign changes to the element matrix */ 8106 if (values && flips[f]) { 8107 PetscInt foffset = offsets[f]; 8108 8109 for (p = 0; p < Ncl; ++p) { 8110 PetscInt pnt = points[2 * p], fdof; 8111 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8112 8113 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8114 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8115 if (flip) { 8116 PetscInt i, j, k; 8117 8118 if (!valCopy) { 8119 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8120 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8121 *values = valCopy; 8122 } 8123 for (i = 0; i < fdof; ++i) { 8124 PetscScalar fval = flip[i]; 8125 8126 if (multiplyRight) { 8127 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8128 } 8129 if (multiplyLeft) { 8130 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8131 } 8132 } 8133 } 8134 foffset += fdof; 8135 } 8136 } 8137 } 8138 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8139 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8140 if (NclC) { 8141 if (multiplyRight) *numCols = NiC; 8142 if (multiplyLeft) *numRows = NiC; 8143 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8144 for (f = 0; f < PetscMax(1, Nf); ++f) { 8145 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8146 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8147 } 8148 for (f = 0; f < PetscMax(1, Nf); ++f) { 8149 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8150 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8151 } 8152 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8153 Ncl = NclC; 8154 Ni = NiC; 8155 points = pointsC; 8156 if (values) *values = valuesC; 8157 } 8158 /* 5) Calculate indices */ 8159 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8160 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8161 if (Nf) { 8162 PetscInt idxOff; 8163 PetscBool useFieldOffsets; 8164 8165 if (outOffsets) { 8166 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8167 } 8168 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8169 if (useFieldOffsets) { 8170 for (p = 0; p < Ncl; ++p) { 8171 const PetscInt pnt = points[p * 2]; 8172 8173 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8174 } 8175 } else { 8176 for (p = 0; p < Ncl; ++p) { 8177 const PetscInt pnt = points[p * 2]; 8178 8179 if (pnt < idxStart || pnt >= idxEnd) continue; 8180 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8181 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8182 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8183 * global section. */ 8184 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8185 } 8186 } 8187 } else { 8188 PetscInt off = 0, idxOff; 8189 8190 for (p = 0; p < Ncl; ++p) { 8191 const PetscInt pnt = points[p * 2]; 8192 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8193 8194 if (pnt < idxStart || pnt >= idxEnd) continue; 8195 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8196 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8197 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8198 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8199 } 8200 } 8201 /* 6) Cleanup */ 8202 for (f = 0; f < PetscMax(1, Nf); ++f) { 8203 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8204 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8205 } 8206 if (NclC) { 8207 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8208 } else { 8209 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8210 } 8211 8212 if (indices) *indices = idx; 8213 PetscFunctionReturn(PETSC_SUCCESS); 8214 } 8215 8216 /*@C 8217 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8218 8219 Not collective 8220 8221 Input Parameters: 8222 + dm - The `DM` 8223 . section - The `PetscSection` describing the points (a local section) 8224 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8225 . point - The point defining the closure 8226 - useClPerm - Use the closure point permutation if available 8227 8228 Output Parameters: 8229 + numIndices - The number of dof indices in the closure of point with the input sections 8230 . indices - The dof indices 8231 . outOffsets - Array to write the field offsets into, or `NULL` 8232 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8233 8234 Level: advanced 8235 8236 Notes: 8237 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8238 8239 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8240 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8241 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8242 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8243 indices (with the above semantics) are implied. 8244 8245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8246 `PetscSection`, `DMGetGlobalSection()` 8247 @*/ 8248 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8249 { 8250 PetscInt numRows = -1, numCols = -1; 8251 8252 PetscFunctionBeginHot; 8253 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8254 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8255 *numIndices = numRows; 8256 PetscFunctionReturn(PETSC_SUCCESS); 8257 } 8258 8259 /*@C 8260 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8261 8262 Not collective 8263 8264 Input Parameters: 8265 + dm - The `DM` 8266 . section - The `PetscSection` describing the points (a local section) 8267 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8268 . point - The point defining the closure 8269 - useClPerm - Use the closure point permutation if available 8270 8271 Output Parameters: 8272 + numIndices - The number of dof indices in the closure of point with the input sections 8273 . indices - The dof indices 8274 . outOffsets - Array to write the field offsets into, or `NULL` 8275 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8276 8277 Level: advanced 8278 8279 Notes: 8280 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8281 8282 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8283 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8284 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8285 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8286 indices (with the above semantics) are implied. 8287 8288 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8289 @*/ 8290 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PeOp PetscInt outOffsets[], PeOp PetscScalar *values[]) 8291 { 8292 PetscFunctionBegin; 8293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8294 PetscAssertPointer(indices, 7); 8295 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8296 PetscFunctionReturn(PETSC_SUCCESS); 8297 } 8298 8299 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8300 { 8301 DM_Plex *mesh = (DM_Plex *)dm->data; 8302 PetscInt *indices; 8303 PetscInt numIndices; 8304 const PetscScalar *valuesOrig = values; 8305 PetscErrorCode ierr; 8306 8307 PetscFunctionBegin; 8308 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8309 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8310 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8311 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8312 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8313 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8314 8315 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8316 8317 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8318 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8319 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8320 if (ierr) { 8321 PetscMPIInt rank; 8322 8323 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8324 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8325 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8326 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8327 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8328 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8329 } 8330 if (mesh->printFEM > 1) { 8331 PetscInt i; 8332 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8333 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8334 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8335 } 8336 8337 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8338 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8339 PetscFunctionReturn(PETSC_SUCCESS); 8340 } 8341 8342 /*@C 8343 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8344 8345 Not collective 8346 8347 Input Parameters: 8348 + dm - The `DM` 8349 . section - The section describing the layout in `v`, or `NULL` to use the default section 8350 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8351 . A - The matrix 8352 . point - The point in the `DM` 8353 . values - The array of values 8354 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8355 8356 Level: intermediate 8357 8358 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8359 @*/ 8360 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8361 { 8362 PetscFunctionBegin; 8363 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8364 PetscFunctionReturn(PETSC_SUCCESS); 8365 } 8366 8367 /*@C 8368 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8369 8370 Not collective 8371 8372 Input Parameters: 8373 + dmRow - The `DM` for the row fields 8374 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8375 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8376 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8377 . dmCol - The `DM` for the column fields 8378 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8379 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8380 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8381 . A - The matrix 8382 . point - The point in the `DM` 8383 . values - The array of values 8384 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8385 8386 Level: intermediate 8387 8388 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8389 @*/ 8390 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) 8391 { 8392 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8393 PetscInt *indicesRow, *indicesCol; 8394 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8395 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8396 8397 PetscErrorCode ierr; 8398 8399 PetscFunctionBegin; 8400 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8401 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8402 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8403 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8404 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8405 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8406 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8407 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8408 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8409 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8410 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8411 8412 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8413 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8414 valuesV1 = valuesV0; 8415 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8416 valuesV2 = valuesV1; 8417 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8418 8419 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8420 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8421 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8422 if (ierr) { 8423 PetscMPIInt rank; 8424 8425 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8426 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8427 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8428 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8429 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8430 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8431 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8432 } 8433 8434 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8435 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8436 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8437 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8438 PetscFunctionReturn(PETSC_SUCCESS); 8439 } 8440 8441 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8442 { 8443 DM_Plex *mesh = (DM_Plex *)dmf->data; 8444 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8445 PetscInt *cpoints = NULL; 8446 PetscInt *findices, *cindices; 8447 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8448 PetscInt foffsets[32], coffsets[32]; 8449 DMPolytopeType ct; 8450 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8451 PetscErrorCode ierr; 8452 8453 PetscFunctionBegin; 8454 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8455 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8456 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8457 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8458 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8459 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8460 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8461 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8462 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8463 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8464 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8465 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8466 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8467 PetscCall(PetscArrayzero(foffsets, 32)); 8468 PetscCall(PetscArrayzero(coffsets, 32)); 8469 /* Column indices */ 8470 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8471 maxFPoints = numCPoints; 8472 /* Compress out points not in the section */ 8473 /* TODO: Squeeze out points with 0 dof as well */ 8474 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8475 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8476 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8477 cpoints[q * 2] = cpoints[p]; 8478 cpoints[q * 2 + 1] = cpoints[p + 1]; 8479 ++q; 8480 } 8481 } 8482 numCPoints = q; 8483 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8484 PetscInt fdof; 8485 8486 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8487 if (!dof) continue; 8488 for (f = 0; f < numFields; ++f) { 8489 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8490 coffsets[f + 1] += fdof; 8491 } 8492 numCIndices += dof; 8493 } 8494 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8495 /* Row indices */ 8496 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8497 { 8498 DMPlexTransform tr; 8499 DMPolytopeType *rct; 8500 PetscInt *rsize, *rcone, *rornt, Nt; 8501 8502 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8503 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8504 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8505 numSubcells = rsize[Nt - 1]; 8506 PetscCall(DMPlexTransformDestroy(&tr)); 8507 } 8508 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8509 for (r = 0, q = 0; r < numSubcells; ++r) { 8510 /* TODO Map from coarse to fine cells */ 8511 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8512 /* Compress out points not in the section */ 8513 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8514 for (p = 0; p < numFPoints * 2; p += 2) { 8515 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8516 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8517 if (!dof) continue; 8518 for (s = 0; s < q; ++s) 8519 if (fpoints[p] == ftotpoints[s * 2]) break; 8520 if (s < q) continue; 8521 ftotpoints[q * 2] = fpoints[p]; 8522 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8523 ++q; 8524 } 8525 } 8526 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8527 } 8528 numFPoints = q; 8529 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8530 PetscInt fdof; 8531 8532 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8533 if (!dof) continue; 8534 for (f = 0; f < numFields; ++f) { 8535 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8536 foffsets[f + 1] += fdof; 8537 } 8538 numFIndices += dof; 8539 } 8540 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8541 8542 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8543 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8544 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8545 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8546 if (numFields) { 8547 const PetscInt **permsF[32] = {NULL}; 8548 const PetscInt **permsC[32] = {NULL}; 8549 8550 for (f = 0; f < numFields; f++) { 8551 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8552 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8553 } 8554 for (p = 0; p < numFPoints; p++) { 8555 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8556 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8557 } 8558 for (p = 0; p < numCPoints; p++) { 8559 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8560 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8561 } 8562 for (f = 0; f < numFields; f++) { 8563 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8564 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8565 } 8566 } else { 8567 const PetscInt **permsF = NULL; 8568 const PetscInt **permsC = NULL; 8569 8570 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8571 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8572 for (p = 0, off = 0; p < numFPoints; p++) { 8573 const PetscInt *perm = permsF ? permsF[p] : NULL; 8574 8575 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8576 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8577 } 8578 for (p = 0, off = 0; p < numCPoints; p++) { 8579 const PetscInt *perm = permsC ? permsC[p] : NULL; 8580 8581 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8582 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8583 } 8584 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8585 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8586 } 8587 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8588 /* TODO: flips */ 8589 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8590 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8591 if (ierr) { 8592 PetscMPIInt rank; 8593 8594 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8595 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8596 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8597 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8598 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8599 } 8600 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8601 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8602 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8603 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8604 PetscFunctionReturn(PETSC_SUCCESS); 8605 } 8606 8607 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8608 { 8609 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8610 PetscInt *cpoints = NULL; 8611 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8612 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8613 DMPolytopeType ct; 8614 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8615 8616 PetscFunctionBegin; 8617 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8618 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8619 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8620 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8621 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8622 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8623 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8624 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8625 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8626 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8627 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8628 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8629 /* Column indices */ 8630 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8631 maxFPoints = numCPoints; 8632 /* Compress out points not in the section */ 8633 /* TODO: Squeeze out points with 0 dof as well */ 8634 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8635 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8636 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8637 cpoints[q * 2] = cpoints[p]; 8638 cpoints[q * 2 + 1] = cpoints[p + 1]; 8639 ++q; 8640 } 8641 } 8642 numCPoints = q; 8643 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8644 PetscInt fdof; 8645 8646 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8647 if (!dof) continue; 8648 for (f = 0; f < numFields; ++f) { 8649 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8650 coffsets[f + 1] += fdof; 8651 } 8652 numCIndices += dof; 8653 } 8654 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8655 /* Row indices */ 8656 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8657 { 8658 DMPlexTransform tr; 8659 DMPolytopeType *rct; 8660 PetscInt *rsize, *rcone, *rornt, Nt; 8661 8662 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8663 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8664 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8665 numSubcells = rsize[Nt - 1]; 8666 PetscCall(DMPlexTransformDestroy(&tr)); 8667 } 8668 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8669 for (r = 0, q = 0; r < numSubcells; ++r) { 8670 /* TODO Map from coarse to fine cells */ 8671 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8672 /* Compress out points not in the section */ 8673 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8674 for (p = 0; p < numFPoints * 2; p += 2) { 8675 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8676 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8677 if (!dof) continue; 8678 for (s = 0; s < q; ++s) 8679 if (fpoints[p] == ftotpoints[s * 2]) break; 8680 if (s < q) continue; 8681 ftotpoints[q * 2] = fpoints[p]; 8682 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8683 ++q; 8684 } 8685 } 8686 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8687 } 8688 numFPoints = q; 8689 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8690 PetscInt fdof; 8691 8692 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8693 if (!dof) continue; 8694 for (f = 0; f < numFields; ++f) { 8695 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8696 foffsets[f + 1] += fdof; 8697 } 8698 numFIndices += dof; 8699 } 8700 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8701 8702 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8703 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8704 if (numFields) { 8705 const PetscInt **permsF[32] = {NULL}; 8706 const PetscInt **permsC[32] = {NULL}; 8707 8708 for (f = 0; f < numFields; f++) { 8709 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8710 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8711 } 8712 for (p = 0; p < numFPoints; p++) { 8713 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8714 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8715 } 8716 for (p = 0; p < numCPoints; p++) { 8717 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8718 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8719 } 8720 for (f = 0; f < numFields; f++) { 8721 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8722 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8723 } 8724 } else { 8725 const PetscInt **permsF = NULL; 8726 const PetscInt **permsC = NULL; 8727 8728 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8729 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8730 for (p = 0, off = 0; p < numFPoints; p++) { 8731 const PetscInt *perm = permsF ? permsF[p] : NULL; 8732 8733 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8734 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8735 } 8736 for (p = 0, off = 0; p < numCPoints; p++) { 8737 const PetscInt *perm = permsC ? permsC[p] : NULL; 8738 8739 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8740 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8741 } 8742 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8743 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8744 } 8745 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8746 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8747 PetscFunctionReturn(PETSC_SUCCESS); 8748 } 8749 8750 /*@ 8751 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8752 8753 Input Parameter: 8754 . dm - The `DMPLEX` object 8755 8756 Output Parameter: 8757 . cellHeight - The height of a cell 8758 8759 Level: developer 8760 8761 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8762 @*/ 8763 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8764 { 8765 DM_Plex *mesh = (DM_Plex *)dm->data; 8766 8767 PetscFunctionBegin; 8768 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8769 PetscAssertPointer(cellHeight, 2); 8770 *cellHeight = mesh->vtkCellHeight; 8771 PetscFunctionReturn(PETSC_SUCCESS); 8772 } 8773 8774 /*@ 8775 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8776 8777 Input Parameters: 8778 + dm - The `DMPLEX` object 8779 - cellHeight - The height of a cell 8780 8781 Level: developer 8782 8783 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8784 @*/ 8785 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8786 { 8787 DM_Plex *mesh = (DM_Plex *)dm->data; 8788 8789 PetscFunctionBegin; 8790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8791 mesh->vtkCellHeight = cellHeight; 8792 PetscFunctionReturn(PETSC_SUCCESS); 8793 } 8794 8795 /*@ 8796 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8797 8798 Input Parameters: 8799 + dm - The `DMPLEX` object 8800 - ct - The `DMPolytopeType` of the cell 8801 8802 Output Parameters: 8803 + start - The first cell of this type, or `NULL` 8804 - end - The upper bound on this celltype, or `NULL` 8805 8806 Level: advanced 8807 8808 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8809 @*/ 8810 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PeOp PetscInt *start, PeOp PetscInt *end) 8811 { 8812 DM_Plex *mesh = (DM_Plex *)dm->data; 8813 DMLabel label; 8814 PetscInt pStart, pEnd; 8815 8816 PetscFunctionBegin; 8817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8818 if (start) { 8819 PetscAssertPointer(start, 3); 8820 *start = 0; 8821 } 8822 if (end) { 8823 PetscAssertPointer(end, 4); 8824 *end = 0; 8825 } 8826 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8827 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8828 if (mesh->tr) { 8829 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8830 } else { 8831 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8832 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8833 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8834 } 8835 PetscFunctionReturn(PETSC_SUCCESS); 8836 } 8837 8838 /*@ 8839 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8840 8841 Input Parameters: 8842 + dm - The `DMPLEX` object 8843 - depth - The depth for the given point stratum 8844 8845 Output Parameter: 8846 . gsize - The global number of points in the stratum 8847 8848 Level: advanced 8849 8850 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8851 @*/ 8852 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8853 { 8854 PetscSF sf; 8855 const PetscInt *leaves; 8856 PetscInt Nl, loc, start, end, lsize = 0; 8857 8858 PetscFunctionBegin; 8859 PetscCall(DMGetPointSF(dm, &sf)); 8860 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8861 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8862 for (PetscInt p = start; p < end; ++p) { 8863 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8864 if (loc < 0) ++lsize; 8865 } 8866 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8867 PetscFunctionReturn(PETSC_SUCCESS); 8868 } 8869 8870 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8871 { 8872 PetscSection section, globalSection; 8873 PetscInt *numbers, p; 8874 8875 PetscFunctionBegin; 8876 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8877 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8878 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8879 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8880 PetscCall(PetscSectionSetUp(section)); 8881 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8882 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8883 for (p = pStart; p < pEnd; ++p) { 8884 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8885 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8886 else numbers[p - pStart] += shift; 8887 } 8888 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8889 if (globalSize) { 8890 PetscLayout layout; 8891 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8892 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8893 PetscCall(PetscLayoutDestroy(&layout)); 8894 } 8895 PetscCall(PetscSectionDestroy(§ion)); 8896 PetscCall(PetscSectionDestroy(&globalSection)); 8897 PetscFunctionReturn(PETSC_SUCCESS); 8898 } 8899 8900 /*@ 8901 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8902 8903 Input Parameters: 8904 + dm - The `DMPLEX` object 8905 - includeAll - Whether to include all cells, or just the simplex and box cells 8906 8907 Output Parameter: 8908 . globalCellNumbers - Global cell numbers for all cells on this process 8909 8910 Level: developer 8911 8912 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8913 @*/ 8914 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8915 { 8916 PetscInt cellHeight, cStart, cEnd; 8917 8918 PetscFunctionBegin; 8919 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8920 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8921 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8922 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8923 PetscFunctionReturn(PETSC_SUCCESS); 8924 } 8925 8926 /*@ 8927 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8928 8929 Input Parameter: 8930 . dm - The `DMPLEX` object 8931 8932 Output Parameter: 8933 . globalCellNumbers - Global cell numbers for all cells on this process 8934 8935 Level: developer 8936 8937 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8938 @*/ 8939 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8940 { 8941 DM_Plex *mesh = (DM_Plex *)dm->data; 8942 8943 PetscFunctionBegin; 8944 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8945 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8946 *globalCellNumbers = mesh->globalCellNumbers; 8947 PetscFunctionReturn(PETSC_SUCCESS); 8948 } 8949 8950 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8951 { 8952 PetscInt vStart, vEnd; 8953 8954 PetscFunctionBegin; 8955 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8956 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8957 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8958 PetscFunctionReturn(PETSC_SUCCESS); 8959 } 8960 8961 /*@ 8962 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8963 8964 Input Parameter: 8965 . dm - The `DMPLEX` object 8966 8967 Output Parameter: 8968 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8969 8970 Level: developer 8971 8972 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8973 @*/ 8974 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8975 { 8976 DM_Plex *mesh = (DM_Plex *)dm->data; 8977 8978 PetscFunctionBegin; 8979 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8980 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8981 *globalVertexNumbers = mesh->globalVertexNumbers; 8982 PetscFunctionReturn(PETSC_SUCCESS); 8983 } 8984 8985 /*@ 8986 DMPlexCreatePointNumbering - Create a global numbering for all points. 8987 8988 Collective 8989 8990 Input Parameter: 8991 . dm - The `DMPLEX` object 8992 8993 Output Parameter: 8994 . globalPointNumbers - Global numbers for all points on this process 8995 8996 Level: developer 8997 8998 Notes: 8999 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 9000 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 9001 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 9002 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 9003 9004 The partitioned mesh is 9005 ``` 9006 (2)--0--(3)--1--(4) (1)--0--(2) 9007 ``` 9008 and its global numbering is 9009 ``` 9010 (3)--0--(4)--1--(5)--2--(6) 9011 ``` 9012 Then the global numbering is provided as 9013 ``` 9014 [0] Number of indices in set 5 9015 [0] 0 0 9016 [0] 1 1 9017 [0] 2 3 9018 [0] 3 4 9019 [0] 4 -6 9020 [1] Number of indices in set 3 9021 [1] 0 2 9022 [1] 1 5 9023 [1] 2 6 9024 ``` 9025 9026 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 9027 @*/ 9028 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9029 { 9030 IS nums[4]; 9031 PetscInt depths[4], gdepths[4], starts[4]; 9032 PetscInt depth, d, shift = 0; 9033 PetscBool empty = PETSC_FALSE; 9034 9035 PetscFunctionBegin; 9036 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9037 PetscCall(DMPlexGetDepth(dm, &depth)); 9038 // For unstratified meshes use dim instead of depth 9039 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9040 // If any stratum is empty, we must mark all empty 9041 for (d = 0; d <= depth; ++d) { 9042 PetscInt end; 9043 9044 depths[d] = depth - d; 9045 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9046 if (!(starts[d] - end)) empty = PETSC_TRUE; 9047 } 9048 if (empty) 9049 for (d = 0; d <= depth; ++d) { 9050 depths[d] = -1; 9051 starts[d] = -1; 9052 } 9053 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9054 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9055 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]); 9056 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9057 for (d = 0; d <= depth; ++d) { 9058 PetscInt pStart, pEnd, gsize; 9059 9060 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9061 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9062 shift += gsize; 9063 } 9064 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9065 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9066 PetscFunctionReturn(PETSC_SUCCESS); 9067 } 9068 9069 /*@ 9070 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9071 9072 Collective 9073 9074 Input Parameter: 9075 . dm - The `DMPLEX` object 9076 9077 Output Parameter: 9078 . globalEdgeNumbers - Global numbers for all edges on this process 9079 9080 Level: developer 9081 9082 Notes: 9083 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). 9084 9085 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9086 @*/ 9087 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9088 { 9089 PetscSF sf; 9090 PetscInt eStart, eEnd; 9091 9092 PetscFunctionBegin; 9093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9094 PetscCall(DMGetPointSF(dm, &sf)); 9095 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9096 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9097 PetscFunctionReturn(PETSC_SUCCESS); 9098 } 9099 9100 /*@ 9101 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9102 9103 Input Parameter: 9104 . dm - The `DMPLEX` object 9105 9106 Output Parameter: 9107 . ranks - The rank field 9108 9109 Options Database Key: 9110 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9111 9112 Level: intermediate 9113 9114 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9115 @*/ 9116 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9117 { 9118 DM rdm; 9119 PetscFE fe; 9120 PetscScalar *r; 9121 PetscMPIInt rank; 9122 DMPolytopeType ct; 9123 PetscInt dim, cStart, cEnd, c; 9124 PetscBool simplex; 9125 9126 PetscFunctionBeginUser; 9127 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9128 PetscAssertPointer(ranks, 2); 9129 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9130 PetscCall(DMClone(dm, &rdm)); 9131 PetscCall(DMGetDimension(rdm, &dim)); 9132 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9133 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9134 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9135 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9136 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9137 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9138 PetscCall(PetscFEDestroy(&fe)); 9139 PetscCall(DMCreateDS(rdm)); 9140 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9141 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9142 PetscCall(VecGetArray(*ranks, &r)); 9143 for (c = cStart; c < cEnd; ++c) { 9144 PetscScalar *lr; 9145 9146 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9147 if (lr) *lr = rank; 9148 } 9149 PetscCall(VecRestoreArray(*ranks, &r)); 9150 PetscCall(DMDestroy(&rdm)); 9151 PetscFunctionReturn(PETSC_SUCCESS); 9152 } 9153 9154 /*@ 9155 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9156 9157 Input Parameters: 9158 + dm - The `DMPLEX` 9159 - label - The `DMLabel` 9160 9161 Output Parameter: 9162 . val - The label value field 9163 9164 Options Database Key: 9165 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9166 9167 Level: intermediate 9168 9169 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9170 @*/ 9171 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9172 { 9173 DM rdm, plex; 9174 Vec lval; 9175 PetscSection section; 9176 PetscFE fe; 9177 PetscScalar *v; 9178 PetscInt dim, pStart, pEnd, p, cStart; 9179 DMPolytopeType ct; 9180 char name[PETSC_MAX_PATH_LEN]; 9181 const char *lname, *prefix; 9182 9183 PetscFunctionBeginUser; 9184 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9185 PetscAssertPointer(label, 2); 9186 PetscAssertPointer(val, 3); 9187 PetscCall(DMClone(dm, &rdm)); 9188 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9189 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9190 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9191 PetscCall(DMDestroy(&plex)); 9192 PetscCall(DMGetDimension(rdm, &dim)); 9193 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9194 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9195 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9196 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9197 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9198 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9199 PetscCall(PetscFEDestroy(&fe)); 9200 PetscCall(DMCreateDS(rdm)); 9201 PetscCall(DMCreateGlobalVector(rdm, val)); 9202 PetscCall(DMCreateLocalVector(rdm, &lval)); 9203 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9204 PetscCall(DMGetLocalSection(rdm, §ion)); 9205 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9206 PetscCall(VecGetArray(lval, &v)); 9207 for (p = pStart; p < pEnd; ++p) { 9208 PetscInt cval, dof, off; 9209 9210 PetscCall(PetscSectionGetDof(section, p, &dof)); 9211 if (!dof) continue; 9212 PetscCall(DMLabelGetValue(label, p, &cval)); 9213 PetscCall(PetscSectionGetOffset(section, p, &off)); 9214 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9215 } 9216 PetscCall(VecRestoreArray(lval, &v)); 9217 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9218 PetscCall(VecDestroy(&lval)); 9219 PetscCall(DMDestroy(&rdm)); 9220 PetscFunctionReturn(PETSC_SUCCESS); 9221 } 9222 9223 /*@ 9224 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9225 9226 Input Parameter: 9227 . dm - The `DMPLEX` object 9228 9229 Level: developer 9230 9231 Notes: 9232 This is a useful diagnostic when creating meshes programmatically. 9233 9234 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9235 9236 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9237 @*/ 9238 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9239 { 9240 PetscSection coneSection, supportSection; 9241 const PetscInt *cone, *support; 9242 PetscInt coneSize, c, supportSize, s; 9243 PetscInt pStart, pEnd, p, pp, csize, ssize; 9244 PetscBool storagecheck = PETSC_TRUE; 9245 9246 PetscFunctionBegin; 9247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9248 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9249 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9250 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9251 /* Check that point p is found in the support of its cone points, and vice versa */ 9252 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9253 for (p = pStart; p < pEnd; ++p) { 9254 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9255 PetscCall(DMPlexGetCone(dm, p, &cone)); 9256 for (c = 0; c < coneSize; ++c) { 9257 PetscBool dup = PETSC_FALSE; 9258 PetscInt d; 9259 for (d = c - 1; d >= 0; --d) { 9260 if (cone[c] == cone[d]) { 9261 dup = PETSC_TRUE; 9262 break; 9263 } 9264 } 9265 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9266 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9267 for (s = 0; s < supportSize; ++s) { 9268 if (support[s] == p) break; 9269 } 9270 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9271 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9272 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9273 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9274 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9275 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9276 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9277 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]); 9278 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9279 } 9280 } 9281 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9282 if (p != pp) { 9283 storagecheck = PETSC_FALSE; 9284 continue; 9285 } 9286 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9287 PetscCall(DMPlexGetSupport(dm, p, &support)); 9288 for (s = 0; s < supportSize; ++s) { 9289 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9290 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9291 for (c = 0; c < coneSize; ++c) { 9292 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9293 if (cone[c] != pp) { 9294 c = 0; 9295 break; 9296 } 9297 if (cone[c] == p) break; 9298 } 9299 if (c >= coneSize) { 9300 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9301 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9302 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9303 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9304 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9305 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9306 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9307 } 9308 } 9309 } 9310 if (storagecheck) { 9311 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9312 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9313 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9314 } 9315 PetscFunctionReturn(PETSC_SUCCESS); 9316 } 9317 9318 /* 9319 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. 9320 */ 9321 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9322 { 9323 DMPolytopeType cct; 9324 PetscInt ptpoints[4]; 9325 const PetscInt *cone, *ccone, *ptcone; 9326 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9327 9328 PetscFunctionBegin; 9329 *unsplit = 0; 9330 switch (ct) { 9331 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9332 ptpoints[npt++] = c; 9333 break; 9334 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9335 PetscCall(DMPlexGetCone(dm, c, &cone)); 9336 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9337 for (cp = 0; cp < coneSize; ++cp) { 9338 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9339 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9340 } 9341 break; 9342 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9343 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9344 PetscCall(DMPlexGetCone(dm, c, &cone)); 9345 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9346 for (cp = 0; cp < coneSize; ++cp) { 9347 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9348 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9349 for (ccp = 0; ccp < cconeSize; ++ccp) { 9350 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9351 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9352 PetscInt p; 9353 for (p = 0; p < npt; ++p) 9354 if (ptpoints[p] == ccone[ccp]) break; 9355 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9356 } 9357 } 9358 } 9359 break; 9360 default: 9361 break; 9362 } 9363 for (pt = 0; pt < npt; ++pt) { 9364 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9365 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9366 } 9367 PetscFunctionReturn(PETSC_SUCCESS); 9368 } 9369 9370 /*@ 9371 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9372 9373 Input Parameters: 9374 + dm - The `DMPLEX` object 9375 - cellHeight - Normally 0 9376 9377 Level: developer 9378 9379 Notes: 9380 This is a useful diagnostic when creating meshes programmatically. 9381 Currently applicable only to homogeneous simplex or tensor meshes. 9382 9383 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9384 9385 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9386 @*/ 9387 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9388 { 9389 DMPlexInterpolatedFlag interp; 9390 DMPolytopeType ct; 9391 PetscInt vStart, vEnd, cStart, cEnd, c; 9392 9393 PetscFunctionBegin; 9394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9395 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9396 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9397 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9398 for (c = cStart; c < cEnd; ++c) { 9399 PetscInt *closure = NULL; 9400 PetscInt coneSize, closureSize, cl, Nv = 0; 9401 9402 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9403 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9404 if (interp == DMPLEX_INTERPOLATED_FULL) { 9405 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9406 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)); 9407 } 9408 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9409 for (cl = 0; cl < closureSize * 2; cl += 2) { 9410 const PetscInt p = closure[cl]; 9411 if ((p >= vStart) && (p < vEnd)) ++Nv; 9412 } 9413 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9414 /* Special Case: Tensor faces with identified vertices */ 9415 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9416 PetscInt unsplit; 9417 9418 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9419 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9420 } 9421 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)); 9422 } 9423 PetscFunctionReturn(PETSC_SUCCESS); 9424 } 9425 9426 /*@ 9427 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9428 9429 Collective 9430 9431 Input Parameters: 9432 + dm - The `DMPLEX` object 9433 - cellHeight - Normally 0 9434 9435 Level: developer 9436 9437 Notes: 9438 This is a useful diagnostic when creating meshes programmatically. 9439 This routine is only relevant for meshes that are fully interpolated across all ranks. 9440 It will error out if a partially interpolated mesh is given on some rank. 9441 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9442 9443 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9444 9445 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9446 @*/ 9447 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9448 { 9449 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9450 DMPlexInterpolatedFlag interpEnum; 9451 9452 PetscFunctionBegin; 9453 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9454 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9455 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9456 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9457 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9458 PetscFunctionReturn(PETSC_SUCCESS); 9459 } 9460 9461 PetscCall(DMGetDimension(dm, &dim)); 9462 PetscCall(DMPlexGetDepth(dm, &depth)); 9463 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9464 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9465 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9466 for (c = cStart; c < cEnd; ++c) { 9467 const PetscInt *cone, *ornt, *faceSizes, *faces; 9468 const DMPolytopeType *faceTypes; 9469 DMPolytopeType ct; 9470 PetscInt numFaces, coneSize, f; 9471 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9472 9473 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9474 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9475 if (unsplit) continue; 9476 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9477 PetscCall(DMPlexGetCone(dm, c, &cone)); 9478 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9479 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9480 for (cl = 0; cl < closureSize * 2; cl += 2) { 9481 const PetscInt p = closure[cl]; 9482 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9483 } 9484 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9485 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); 9486 for (f = 0; f < numFaces; ++f) { 9487 DMPolytopeType fct; 9488 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9489 9490 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9491 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9492 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9493 const PetscInt p = fclosure[cl]; 9494 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9495 } 9496 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]); 9497 for (v = 0; v < fnumCorners; ++v) { 9498 if (fclosure[v] != faces[fOff + v]) { 9499 PetscInt v1; 9500 9501 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9502 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9503 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9504 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9505 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9506 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]); 9507 } 9508 } 9509 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9510 fOff += faceSizes[f]; 9511 } 9512 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9513 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9514 } 9515 } 9516 PetscFunctionReturn(PETSC_SUCCESS); 9517 } 9518 9519 /*@ 9520 DMPlexCheckGeometry - Check the geometry of mesh cells 9521 9522 Input Parameter: 9523 . dm - The `DMPLEX` object 9524 9525 Level: developer 9526 9527 Notes: 9528 This is a useful diagnostic when creating meshes programmatically. 9529 9530 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9531 9532 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9533 @*/ 9534 PetscErrorCode DMPlexCheckGeometry(DM dm) 9535 { 9536 Vec coordinates; 9537 PetscReal detJ, J[9], refVol = 1.0; 9538 PetscReal vol; 9539 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9540 9541 PetscFunctionBegin; 9542 PetscCall(DMGetDimension(dm, &dim)); 9543 PetscCall(DMGetCoordinateDim(dm, &dE)); 9544 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9545 PetscCall(DMPlexGetDepth(dm, &depth)); 9546 for (d = 0; d < dim; ++d) refVol *= 2.0; 9547 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9548 /* Make sure local coordinates are created, because that step is collective */ 9549 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9550 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9551 for (c = cStart; c < cEnd; ++c) { 9552 DMPolytopeType ct; 9553 PetscInt unsplit; 9554 PetscBool ignoreZeroVol = PETSC_FALSE; 9555 9556 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9557 switch (ct) { 9558 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9559 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9560 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9561 ignoreZeroVol = PETSC_TRUE; 9562 break; 9563 default: 9564 break; 9565 } 9566 switch (ct) { 9567 case DM_POLYTOPE_TRI_PRISM: 9568 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9569 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9570 case DM_POLYTOPE_PYRAMID: 9571 continue; 9572 default: 9573 break; 9574 } 9575 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9576 if (unsplit) continue; 9577 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9578 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); 9579 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9580 /* This should work with periodicity since DG coordinates should be used */ 9581 if (depth > 1) { 9582 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9583 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); 9584 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9585 } 9586 } 9587 PetscFunctionReturn(PETSC_SUCCESS); 9588 } 9589 9590 /*@ 9591 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9592 9593 Collective 9594 9595 Input Parameters: 9596 + dm - The `DMPLEX` object 9597 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9598 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9599 9600 Level: developer 9601 9602 Notes: 9603 This is mainly intended for debugging/testing purposes. 9604 9605 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9606 9607 Extra roots can come from periodic cuts, where additional points appear on the boundary 9608 9609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9610 @*/ 9611 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9612 { 9613 PetscInt l, nleaves, nroots, overlap; 9614 const PetscInt *locals; 9615 const PetscSFNode *remotes; 9616 PetscBool distributed; 9617 MPI_Comm comm; 9618 PetscMPIInt rank; 9619 9620 PetscFunctionBegin; 9621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9622 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9623 else pointSF = dm->sf; 9624 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9625 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9626 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9627 { 9628 PetscMPIInt mpiFlag; 9629 9630 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9631 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9632 } 9633 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9634 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9635 if (!distributed) { 9636 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); 9637 PetscFunctionReturn(PETSC_SUCCESS); 9638 } 9639 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); 9640 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9641 9642 /* Check SF graph is compatible with DMPlex chart */ 9643 { 9644 PetscInt pStart, pEnd, maxLeaf; 9645 9646 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9647 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9648 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9649 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9650 } 9651 9652 /* Check there are no cells in interface */ 9653 if (!overlap) { 9654 PetscInt cellHeight, cStart, cEnd; 9655 9656 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9657 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9658 for (l = 0; l < nleaves; ++l) { 9659 const PetscInt point = locals ? locals[l] : l; 9660 9661 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9662 } 9663 } 9664 9665 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9666 { 9667 const PetscInt *rootdegree; 9668 9669 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9670 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9671 for (l = 0; l < nleaves; ++l) { 9672 const PetscInt point = locals ? locals[l] : l; 9673 const PetscInt *cone; 9674 PetscInt coneSize, c, idx; 9675 9676 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9677 PetscCall(DMPlexGetCone(dm, point, &cone)); 9678 for (c = 0; c < coneSize; ++c) { 9679 if (!rootdegree[cone[c]]) { 9680 if (locals) { 9681 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9682 } else { 9683 idx = (cone[c] < nleaves) ? cone[c] : -1; 9684 } 9685 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9686 } 9687 } 9688 } 9689 } 9690 PetscFunctionReturn(PETSC_SUCCESS); 9691 } 9692 9693 /*@ 9694 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9695 9696 Collective 9697 9698 Input Parameter: 9699 . dm - The `DMPLEX` object 9700 9701 Level: developer 9702 9703 Notes: 9704 This is mainly intended for debugging/testing purposes. 9705 9706 Other cell types which are disconnected would be caught by the symmetry and face checks. 9707 9708 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9709 9710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9711 @*/ 9712 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9713 { 9714 PetscInt pStart, pEnd, vStart, vEnd; 9715 9716 PetscFunctionBegin; 9717 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9718 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9719 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9720 for (PetscInt v = vStart; v < vEnd; ++v) { 9721 PetscInt suppSize; 9722 9723 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9724 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9725 } 9726 PetscFunctionReturn(PETSC_SUCCESS); 9727 } 9728 9729 /*@ 9730 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9731 9732 Input Parameter: 9733 . dm - The `DMPLEX` object 9734 9735 Level: developer 9736 9737 Notes: 9738 This is a useful diagnostic when creating meshes programmatically. 9739 9740 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9741 9742 Currently does not include `DMPlexCheckCellShape()`. 9743 9744 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9745 @*/ 9746 PetscErrorCode DMPlexCheck(DM dm) 9747 { 9748 PetscInt cellHeight; 9749 9750 PetscFunctionBegin; 9751 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9752 PetscCall(DMPlexCheckSymmetry(dm)); 9753 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9754 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9755 PetscCall(DMPlexCheckGeometry(dm)); 9756 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9757 PetscCall(DMPlexCheckInterfaceCones(dm)); 9758 PetscCall(DMPlexCheckOrphanVertices(dm)); 9759 PetscFunctionReturn(PETSC_SUCCESS); 9760 } 9761 9762 typedef struct cell_stats { 9763 PetscReal min, max, sum, squaresum; 9764 PetscInt count; 9765 } cell_stats_t; 9766 9767 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9768 { 9769 PetscInt i, N = *len; 9770 9771 for (i = 0; i < N; i++) { 9772 cell_stats_t *A = (cell_stats_t *)a; 9773 cell_stats_t *B = (cell_stats_t *)b; 9774 9775 B->min = PetscMin(A->min, B->min); 9776 B->max = PetscMax(A->max, B->max); 9777 B->sum += A->sum; 9778 B->squaresum += A->squaresum; 9779 B->count += A->count; 9780 } 9781 } 9782 9783 /*@ 9784 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9785 9786 Collective 9787 9788 Input Parameters: 9789 + dm - The `DMPLEX` object 9790 . output - If true, statistics will be displayed on `stdout` 9791 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9792 9793 Level: developer 9794 9795 Notes: 9796 This is mainly intended for debugging/testing purposes. 9797 9798 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9799 9800 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9801 @*/ 9802 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9803 { 9804 DM dmCoarse; 9805 cell_stats_t stats, globalStats; 9806 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9807 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9808 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9809 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9810 PetscMPIInt rank, size; 9811 9812 PetscFunctionBegin; 9813 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9814 stats.min = PETSC_MAX_REAL; 9815 stats.max = PETSC_MIN_REAL; 9816 stats.sum = stats.squaresum = 0.; 9817 stats.count = 0; 9818 9819 PetscCallMPI(MPI_Comm_size(comm, &size)); 9820 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9821 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9822 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9823 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9824 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9825 for (c = cStart; c < cEnd; c++) { 9826 PetscInt i; 9827 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9828 9829 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9830 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9831 for (i = 0; i < PetscSqr(cdim); ++i) { 9832 frobJ += J[i] * J[i]; 9833 frobInvJ += invJ[i] * invJ[i]; 9834 } 9835 cond2 = frobJ * frobInvJ; 9836 cond = PetscSqrtReal(cond2); 9837 9838 stats.min = PetscMin(stats.min, cond); 9839 stats.max = PetscMax(stats.max, cond); 9840 stats.sum += cond; 9841 stats.squaresum += cond2; 9842 stats.count++; 9843 if (output && cond > limit) { 9844 PetscSection coordSection; 9845 Vec coordsLocal; 9846 PetscScalar *coords = NULL; 9847 PetscInt Nv, d, clSize, cl, *closure = NULL; 9848 9849 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9850 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9851 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9852 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9853 for (i = 0; i < Nv / cdim; ++i) { 9854 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9855 for (d = 0; d < cdim; ++d) { 9856 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9857 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9858 } 9859 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9860 } 9861 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9862 for (cl = 0; cl < clSize * 2; cl += 2) { 9863 const PetscInt edge = closure[cl]; 9864 9865 if ((edge >= eStart) && (edge < eEnd)) { 9866 PetscReal len; 9867 9868 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9869 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9870 } 9871 } 9872 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9873 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9874 } 9875 } 9876 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9877 9878 if (size > 1) { 9879 PetscMPIInt blockLengths[2] = {4, 1}; 9880 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9881 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9882 MPI_Op statReduce; 9883 9884 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9885 PetscCallMPI(MPI_Type_commit(&statType)); 9886 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9887 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9888 PetscCallMPI(MPI_Op_free(&statReduce)); 9889 PetscCallMPI(MPI_Type_free(&statType)); 9890 } else { 9891 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9892 } 9893 if (rank == 0) { 9894 count = globalStats.count; 9895 min = globalStats.min; 9896 max = globalStats.max; 9897 mean = globalStats.sum / globalStats.count; 9898 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9899 } 9900 9901 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)); 9902 PetscCall(PetscFree2(J, invJ)); 9903 9904 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9905 if (dmCoarse) { 9906 PetscBool isplex; 9907 9908 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9909 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9910 } 9911 PetscFunctionReturn(PETSC_SUCCESS); 9912 } 9913 9914 /*@ 9915 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9916 orthogonal quality below given tolerance. 9917 9918 Collective 9919 9920 Input Parameters: 9921 + dm - The `DMPLEX` object 9922 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9923 - atol - [0, 1] Absolute tolerance for tagging cells. 9924 9925 Output Parameters: 9926 + OrthQual - `Vec` containing orthogonal quality per cell 9927 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9928 9929 Options Database Keys: 9930 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9931 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9932 9933 Level: intermediate 9934 9935 Notes: 9936 Orthogonal quality is given by the following formula\: 9937 9938 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9939 9940 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 9941 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9942 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9943 calculating the cosine of the angle between these vectors. 9944 9945 Orthogonal quality ranges from 1 (best) to 0 (worst). 9946 9947 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9948 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9949 9950 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9951 9952 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9953 @*/ 9954 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PeOp PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9955 { 9956 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9957 PetscInt *idx; 9958 PetscScalar *oqVals; 9959 const PetscScalar *cellGeomArr, *faceGeomArr; 9960 PetscReal *ci, *fi, *Ai; 9961 MPI_Comm comm; 9962 Vec cellgeom, facegeom; 9963 DM dmFace, dmCell; 9964 IS glob; 9965 ISLocalToGlobalMapping ltog; 9966 PetscViewer vwr; 9967 9968 PetscFunctionBegin; 9969 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9970 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9971 PetscAssertPointer(OrthQual, 4); 9972 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9973 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9974 PetscCall(DMGetDimension(dm, &nc)); 9975 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9976 { 9977 DMPlexInterpolatedFlag interpFlag; 9978 9979 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9980 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9981 PetscMPIInt rank; 9982 9983 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9984 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9985 } 9986 } 9987 if (OrthQualLabel) { 9988 PetscAssertPointer(OrthQualLabel, 5); 9989 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9990 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9991 } else { 9992 *OrthQualLabel = NULL; 9993 } 9994 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9995 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9996 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9997 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9998 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9999 PetscCall(VecCreate(comm, OrthQual)); 10000 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 10001 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 10002 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 10003 PetscCall(VecSetUp(*OrthQual)); 10004 PetscCall(ISDestroy(&glob)); 10005 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 10006 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 10007 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 10008 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 10009 PetscCall(VecGetDM(cellgeom, &dmCell)); 10010 PetscCall(VecGetDM(facegeom, &dmFace)); 10011 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 10012 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 10013 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 10014 PetscInt cellarr[2], *adj = NULL; 10015 PetscScalar *cArr, *fArr; 10016 PetscReal minvalc = 1.0, minvalf = 1.0; 10017 PetscFVCellGeom *cg; 10018 10019 idx[cellIter] = cell - cStart; 10020 cellarr[0] = cell; 10021 /* Make indexing into cellGeom easier */ 10022 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10023 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10024 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10025 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10026 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10027 PetscInt i; 10028 const PetscInt neigh = adj[cellneigh]; 10029 PetscReal normci = 0, normfi = 0, normai = 0; 10030 PetscFVCellGeom *cgneigh; 10031 PetscFVFaceGeom *fg; 10032 10033 /* Don't count ourselves in the neighbor list */ 10034 if (neigh == cell) continue; 10035 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10036 cellarr[1] = neigh; 10037 { 10038 PetscInt numcovpts; 10039 const PetscInt *covpts; 10040 10041 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10042 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10043 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10044 } 10045 10046 /* Compute c_i, f_i and their norms */ 10047 for (i = 0; i < nc; i++) { 10048 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10049 fi[i] = fg->centroid[i] - cg->centroid[i]; 10050 Ai[i] = fg->normal[i]; 10051 normci += PetscPowReal(ci[i], 2); 10052 normfi += PetscPowReal(fi[i], 2); 10053 normai += PetscPowReal(Ai[i], 2); 10054 } 10055 normci = PetscSqrtReal(normci); 10056 normfi = PetscSqrtReal(normfi); 10057 normai = PetscSqrtReal(normai); 10058 10059 /* Normalize and compute for each face-cell-normal pair */ 10060 for (i = 0; i < nc; i++) { 10061 ci[i] = ci[i] / normci; 10062 fi[i] = fi[i] / normfi; 10063 Ai[i] = Ai[i] / normai; 10064 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10065 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10066 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10067 } 10068 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10069 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10070 } 10071 PetscCall(PetscFree(adj)); 10072 PetscCall(PetscFree2(cArr, fArr)); 10073 /* Defer to cell if they're equal */ 10074 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10075 if (OrthQualLabel) { 10076 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10077 } 10078 } 10079 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10080 PetscCall(VecAssemblyBegin(*OrthQual)); 10081 PetscCall(VecAssemblyEnd(*OrthQual)); 10082 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10083 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10084 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10085 if (OrthQualLabel) { 10086 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10087 } 10088 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10089 PetscCall(PetscViewerDestroy(&vwr)); 10090 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10091 PetscFunctionReturn(PETSC_SUCCESS); 10092 } 10093 10094 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10095 * interpolator construction */ 10096 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10097 { 10098 PetscSection section, newSection, gsection; 10099 PetscSF sf; 10100 PetscBool hasConstraints, ghasConstraints; 10101 10102 PetscFunctionBegin; 10103 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10104 PetscAssertPointer(odm, 2); 10105 PetscCall(DMGetLocalSection(dm, §ion)); 10106 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10107 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10108 if (!ghasConstraints) { 10109 PetscCall(PetscObjectReference((PetscObject)dm)); 10110 *odm = dm; 10111 PetscFunctionReturn(PETSC_SUCCESS); 10112 } 10113 PetscCall(DMClone(dm, odm)); 10114 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10115 PetscCall(DMGetLocalSection(*odm, &newSection)); 10116 PetscCall(DMGetPointSF(*odm, &sf)); 10117 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10118 PetscCall(DMSetGlobalSection(*odm, gsection)); 10119 PetscCall(PetscSectionDestroy(&gsection)); 10120 PetscFunctionReturn(PETSC_SUCCESS); 10121 } 10122 10123 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10124 { 10125 DM dmco, dmfo; 10126 Mat interpo; 10127 Vec rscale; 10128 Vec cglobalo, clocal; 10129 Vec fglobal, fglobalo, flocal; 10130 PetscBool regular; 10131 10132 PetscFunctionBegin; 10133 PetscCall(DMGetFullDM(dmc, &dmco)); 10134 PetscCall(DMGetFullDM(dmf, &dmfo)); 10135 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10136 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10137 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10138 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10139 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10140 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10141 PetscCall(VecSet(cglobalo, 0.)); 10142 PetscCall(VecSet(clocal, 0.)); 10143 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10144 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10145 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10146 PetscCall(VecSet(fglobal, 0.)); 10147 PetscCall(VecSet(fglobalo, 0.)); 10148 PetscCall(VecSet(flocal, 0.)); 10149 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10150 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10151 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10152 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10153 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10154 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10155 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10156 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10157 *shift = fglobal; 10158 PetscCall(VecDestroy(&flocal)); 10159 PetscCall(VecDestroy(&fglobalo)); 10160 PetscCall(VecDestroy(&clocal)); 10161 PetscCall(VecDestroy(&cglobalo)); 10162 PetscCall(VecDestroy(&rscale)); 10163 PetscCall(MatDestroy(&interpo)); 10164 PetscCall(DMDestroy(&dmfo)); 10165 PetscCall(DMDestroy(&dmco)); 10166 PetscFunctionReturn(PETSC_SUCCESS); 10167 } 10168 10169 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10170 { 10171 PetscObject shifto; 10172 Vec shift; 10173 10174 PetscFunctionBegin; 10175 if (!interp) { 10176 Vec rscale; 10177 10178 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10179 PetscCall(VecDestroy(&rscale)); 10180 } else { 10181 PetscCall(PetscObjectReference((PetscObject)interp)); 10182 } 10183 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10184 if (!shifto) { 10185 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10186 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10187 shifto = (PetscObject)shift; 10188 PetscCall(VecDestroy(&shift)); 10189 } 10190 shift = (Vec)shifto; 10191 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10192 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10193 PetscCall(MatDestroy(&interp)); 10194 PetscFunctionReturn(PETSC_SUCCESS); 10195 } 10196 10197 /* Pointwise interpolation 10198 Just code FEM for now 10199 u^f = I u^c 10200 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10201 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10202 I_{ij} = psi^f_i phi^c_j 10203 */ 10204 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10205 { 10206 PetscSection gsc, gsf; 10207 PetscInt m, n; 10208 void *ctx; 10209 DM cdm; 10210 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10211 10212 PetscFunctionBegin; 10213 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10214 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10215 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10216 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10217 10218 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10219 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10220 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10221 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10222 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10223 10224 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10225 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10226 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10227 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10228 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10229 if (scaling) { 10230 /* Use naive scaling */ 10231 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10232 } 10233 PetscFunctionReturn(PETSC_SUCCESS); 10234 } 10235 10236 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10237 { 10238 VecScatter ctx; 10239 10240 PetscFunctionBegin; 10241 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10242 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10243 PetscCall(VecScatterDestroy(&ctx)); 10244 PetscFunctionReturn(PETSC_SUCCESS); 10245 } 10246 10247 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[]) 10248 { 10249 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10250 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10251 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10252 } 10253 10254 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10255 { 10256 DM dmc; 10257 PetscDS ds; 10258 Vec ones, locmass; 10259 IS cellIS; 10260 PetscFormKey key; 10261 PetscInt depth; 10262 10263 PetscFunctionBegin; 10264 PetscCall(DMClone(dm, &dmc)); 10265 PetscCall(DMCopyDisc(dm, dmc)); 10266 PetscCall(DMGetDS(dmc, &ds)); 10267 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10268 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10269 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10270 else PetscCall(DMGetLocalVector(dm, &locmass)); 10271 PetscCall(DMGetLocalVector(dm, &ones)); 10272 PetscCall(DMPlexGetDepth(dm, &depth)); 10273 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10274 PetscCall(VecSet(locmass, 0.0)); 10275 PetscCall(VecSet(ones, 1.0)); 10276 key.label = NULL; 10277 key.value = 0; 10278 key.field = 0; 10279 key.part = 0; 10280 PetscCall(DMPlexComputeJacobianActionByKey(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10281 PetscCall(ISDestroy(&cellIS)); 10282 if (mass) { 10283 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10284 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10285 } 10286 PetscCall(DMRestoreLocalVector(dm, &ones)); 10287 if (lmass) *lmass = locmass; 10288 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10289 PetscCall(DMDestroy(&dmc)); 10290 PetscFunctionReturn(PETSC_SUCCESS); 10291 } 10292 10293 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10294 { 10295 PetscSection gsc, gsf; 10296 PetscInt m, n; 10297 void *ctx; 10298 DM cdm; 10299 PetscBool regular; 10300 10301 PetscFunctionBegin; 10302 if (dmFine == dmCoarse) { 10303 DM dmc; 10304 PetscDS ds; 10305 PetscWeakForm wf; 10306 Vec u; 10307 IS cellIS; 10308 PetscFormKey key; 10309 PetscInt depth; 10310 10311 PetscCall(DMClone(dmFine, &dmc)); 10312 PetscCall(DMCopyDisc(dmFine, dmc)); 10313 PetscCall(DMGetDS(dmc, &ds)); 10314 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10315 PetscCall(PetscWeakFormClear(wf)); 10316 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10317 PetscCall(DMCreateMatrix(dmc, mass)); 10318 PetscCall(DMGetLocalVector(dmc, &u)); 10319 PetscCall(DMPlexGetDepth(dmc, &depth)); 10320 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10321 PetscCall(MatZeroEntries(*mass)); 10322 key.label = NULL; 10323 key.value = 0; 10324 key.field = 0; 10325 key.part = 0; 10326 PetscCall(DMPlexComputeJacobianByKey(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10327 PetscCall(ISDestroy(&cellIS)); 10328 PetscCall(DMRestoreLocalVector(dmc, &u)); 10329 PetscCall(DMDestroy(&dmc)); 10330 } else { 10331 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10332 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10333 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10334 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10335 10336 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10337 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10338 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10339 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10340 10341 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10342 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10343 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10344 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10345 } 10346 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10347 PetscFunctionReturn(PETSC_SUCCESS); 10348 } 10349 10350 /*@ 10351 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10352 10353 Input Parameter: 10354 . dm - The `DMPLEX` object 10355 10356 Output Parameter: 10357 . regular - The flag 10358 10359 Level: intermediate 10360 10361 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10362 @*/ 10363 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10364 { 10365 PetscFunctionBegin; 10366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10367 PetscAssertPointer(regular, 2); 10368 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10369 PetscFunctionReturn(PETSC_SUCCESS); 10370 } 10371 10372 /*@ 10373 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10374 10375 Input Parameters: 10376 + dm - The `DMPLEX` object 10377 - regular - The flag 10378 10379 Level: intermediate 10380 10381 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10382 @*/ 10383 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10384 { 10385 PetscFunctionBegin; 10386 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10387 ((DM_Plex *)dm->data)->regularRefinement = regular; 10388 PetscFunctionReturn(PETSC_SUCCESS); 10389 } 10390 10391 /*@ 10392 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10393 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10394 10395 Not Collective 10396 10397 Input Parameter: 10398 . dm - The `DMPLEX` object 10399 10400 Output Parameters: 10401 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10402 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10403 10404 Level: intermediate 10405 10406 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10407 @*/ 10408 PetscErrorCode DMPlexGetAnchors(DM dm, PeOp PetscSection *anchorSection, PeOp IS *anchorIS) 10409 { 10410 DM_Plex *plex = (DM_Plex *)dm->data; 10411 10412 PetscFunctionBegin; 10413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10414 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10415 if (anchorSection) *anchorSection = plex->anchorSection; 10416 if (anchorIS) *anchorIS = plex->anchorIS; 10417 PetscFunctionReturn(PETSC_SUCCESS); 10418 } 10419 10420 /*@ 10421 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10422 10423 Collective 10424 10425 Input Parameters: 10426 + dm - The `DMPLEX` object 10427 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10428 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10429 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10430 10431 Level: intermediate 10432 10433 Notes: 10434 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10435 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10436 combination of other points' degrees of freedom. 10437 10438 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10439 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10440 10441 The reference counts of `anchorSection` and `anchorIS` are incremented. 10442 10443 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10444 @*/ 10445 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10446 { 10447 DM_Plex *plex = (DM_Plex *)dm->data; 10448 PetscMPIInt result; 10449 10450 PetscFunctionBegin; 10451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10452 if (anchorSection) { 10453 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10454 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10455 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10456 } 10457 if (anchorIS) { 10458 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10459 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10460 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10461 } 10462 10463 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10464 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10465 plex->anchorSection = anchorSection; 10466 10467 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10468 PetscCall(ISDestroy(&plex->anchorIS)); 10469 plex->anchorIS = anchorIS; 10470 10471 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10472 PetscInt size, a, pStart, pEnd; 10473 const PetscInt *anchors; 10474 10475 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10476 PetscCall(ISGetLocalSize(anchorIS, &size)); 10477 PetscCall(ISGetIndices(anchorIS, &anchors)); 10478 for (a = 0; a < size; a++) { 10479 PetscInt p; 10480 10481 p = anchors[a]; 10482 if (p >= pStart && p < pEnd) { 10483 PetscInt dof; 10484 10485 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10486 if (dof) { 10487 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10488 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10489 } 10490 } 10491 } 10492 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10493 } 10494 /* reset the generic constraints */ 10495 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10496 PetscFunctionReturn(PETSC_SUCCESS); 10497 } 10498 10499 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10500 { 10501 PetscSection anchorSection; 10502 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10503 10504 PetscFunctionBegin; 10505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10506 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10507 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10508 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10509 if (numFields) { 10510 PetscInt f; 10511 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10512 10513 for (f = 0; f < numFields; f++) { 10514 PetscInt numComp; 10515 10516 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10517 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10518 } 10519 } 10520 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10521 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10522 pStart = PetscMax(pStart, sStart); 10523 pEnd = PetscMin(pEnd, sEnd); 10524 pEnd = PetscMax(pStart, pEnd); 10525 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10526 for (p = pStart; p < pEnd; p++) { 10527 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10528 if (dof) { 10529 PetscCall(PetscSectionGetDof(section, p, &dof)); 10530 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10531 for (f = 0; f < numFields; f++) { 10532 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10533 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10534 } 10535 } 10536 } 10537 PetscCall(PetscSectionSetUp(*cSec)); 10538 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10539 PetscFunctionReturn(PETSC_SUCCESS); 10540 } 10541 10542 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10543 { 10544 PetscSection aSec; 10545 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10546 const PetscInt *anchors; 10547 PetscInt numFields, f; 10548 IS aIS; 10549 MatType mtype; 10550 PetscBool iscuda, iskokkos; 10551 10552 PetscFunctionBegin; 10553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10554 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10555 PetscCall(PetscSectionGetStorageSize(section, &n)); 10556 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10557 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10558 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10559 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10560 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10561 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10562 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10563 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10564 else mtype = MATSEQAIJ; 10565 PetscCall(MatSetType(*cMat, mtype)); 10566 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10567 PetscCall(ISGetIndices(aIS, &anchors)); 10568 /* cSec will be a subset of aSec and section */ 10569 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10570 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10571 PetscCall(PetscMalloc1(m + 1, &i)); 10572 i[0] = 0; 10573 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10574 for (p = pStart; p < pEnd; p++) { 10575 PetscInt rDof, rOff, r; 10576 10577 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10578 if (!rDof) continue; 10579 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10580 if (numFields) { 10581 for (f = 0; f < numFields; f++) { 10582 annz = 0; 10583 for (r = 0; r < rDof; r++) { 10584 a = anchors[rOff + r]; 10585 if (a < sStart || a >= sEnd) continue; 10586 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10587 annz += aDof; 10588 } 10589 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10590 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10591 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10592 } 10593 } else { 10594 annz = 0; 10595 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10596 for (q = 0; q < dof; q++) { 10597 a = anchors[rOff + q]; 10598 if (a < sStart || a >= sEnd) continue; 10599 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10600 annz += aDof; 10601 } 10602 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10603 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10604 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10605 } 10606 } 10607 nnz = i[m]; 10608 PetscCall(PetscMalloc1(nnz, &j)); 10609 offset = 0; 10610 for (p = pStart; p < pEnd; p++) { 10611 if (numFields) { 10612 for (f = 0; f < numFields; f++) { 10613 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10614 for (q = 0; q < dof; q++) { 10615 PetscInt rDof, rOff, r; 10616 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10617 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10618 for (r = 0; r < rDof; r++) { 10619 PetscInt s; 10620 10621 a = anchors[rOff + r]; 10622 if (a < sStart || a >= sEnd) continue; 10623 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10624 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10625 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10626 } 10627 } 10628 } 10629 } else { 10630 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10631 for (q = 0; q < dof; q++) { 10632 PetscInt rDof, rOff, r; 10633 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10634 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10635 for (r = 0; r < rDof; r++) { 10636 PetscInt s; 10637 10638 a = anchors[rOff + r]; 10639 if (a < sStart || a >= sEnd) continue; 10640 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10641 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10642 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10643 } 10644 } 10645 } 10646 } 10647 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10648 PetscCall(PetscFree(i)); 10649 PetscCall(PetscFree(j)); 10650 PetscCall(ISRestoreIndices(aIS, &anchors)); 10651 PetscFunctionReturn(PETSC_SUCCESS); 10652 } 10653 10654 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10655 { 10656 DM_Plex *plex = (DM_Plex *)dm->data; 10657 PetscSection anchorSection, section, cSec; 10658 Mat cMat; 10659 10660 PetscFunctionBegin; 10661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10662 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10663 if (anchorSection) { 10664 PetscInt Nf; 10665 10666 PetscCall(DMGetLocalSection(dm, §ion)); 10667 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10668 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10669 PetscCall(DMGetNumFields(dm, &Nf)); 10670 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10671 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10672 PetscCall(PetscSectionDestroy(&cSec)); 10673 PetscCall(MatDestroy(&cMat)); 10674 } 10675 PetscFunctionReturn(PETSC_SUCCESS); 10676 } 10677 10678 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10679 { 10680 IS subis; 10681 PetscSection section, subsection; 10682 10683 PetscFunctionBegin; 10684 PetscCall(DMGetLocalSection(dm, §ion)); 10685 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10686 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10687 /* Create subdomain */ 10688 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10689 /* Create submodel */ 10690 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10691 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10692 PetscCall(DMSetLocalSection(*subdm, subsection)); 10693 PetscCall(PetscSectionDestroy(&subsection)); 10694 PetscCall(DMCopyDisc(dm, *subdm)); 10695 /* Create map from submodel to global model */ 10696 if (is) { 10697 PetscSection sectionGlobal, subsectionGlobal; 10698 IS spIS; 10699 const PetscInt *spmap; 10700 PetscInt *subIndices; 10701 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10702 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10703 10704 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10705 PetscCall(ISGetIndices(spIS, &spmap)); 10706 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10707 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10708 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10709 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10710 for (p = pStart; p < pEnd; ++p) { 10711 PetscInt gdof, pSubSize = 0; 10712 10713 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10714 if (gdof > 0) { 10715 for (f = 0; f < Nf; ++f) { 10716 PetscInt fdof, fcdof; 10717 10718 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10719 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10720 pSubSize += fdof - fcdof; 10721 } 10722 subSize += pSubSize; 10723 if (pSubSize) { 10724 if (bs < 0) { 10725 bs = pSubSize; 10726 } else if (bs != pSubSize) { 10727 /* Layout does not admit a pointwise block size */ 10728 bs = 1; 10729 } 10730 } 10731 } 10732 } 10733 /* Must have same blocksize on all procs (some might have no points) */ 10734 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10735 bsLocal[1] = bs; 10736 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10737 if (bsMinMax[0] != bsMinMax[1]) { 10738 bs = 1; 10739 } else { 10740 bs = bsMinMax[0]; 10741 } 10742 PetscCall(PetscMalloc1(subSize, &subIndices)); 10743 for (p = pStart; p < pEnd; ++p) { 10744 PetscInt gdof, goff; 10745 10746 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10747 if (gdof > 0) { 10748 const PetscInt point = spmap[p]; 10749 10750 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10751 for (f = 0; f < Nf; ++f) { 10752 PetscInt fdof, fcdof, fc, f2, poff = 0; 10753 10754 /* Can get rid of this loop by storing field information in the global section */ 10755 for (f2 = 0; f2 < f; ++f2) { 10756 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10757 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10758 poff += fdof - fcdof; 10759 } 10760 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10761 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10762 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10763 } 10764 } 10765 } 10766 PetscCall(ISRestoreIndices(spIS, &spmap)); 10767 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10768 if (bs > 1) { 10769 /* We need to check that the block size does not come from non-contiguous fields */ 10770 PetscInt i, j, set = 1; 10771 for (i = 0; i < subSize; i += bs) { 10772 for (j = 0; j < bs; ++j) { 10773 if (subIndices[i + j] != subIndices[i] + j) { 10774 set = 0; 10775 break; 10776 } 10777 } 10778 } 10779 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10780 } 10781 /* Attach nullspace */ 10782 for (f = 0; f < Nf; ++f) { 10783 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10784 if ((*subdm)->nullspaceConstructors[f]) break; 10785 } 10786 if (f < Nf) { 10787 MatNullSpace nullSpace; 10788 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10789 10790 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10791 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10792 } 10793 } 10794 PetscFunctionReturn(PETSC_SUCCESS); 10795 } 10796 10797 /*@ 10798 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10799 10800 Input Parameters: 10801 + dm - The `DM` 10802 - dummy - unused argument 10803 10804 Options Database Key: 10805 . -dm_plex_monitor_throughput - Activate the monitor 10806 10807 Level: developer 10808 10809 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10810 @*/ 10811 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10812 { 10813 PetscLogHandler default_handler; 10814 10815 PetscFunctionBegin; 10816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10817 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10818 if (default_handler) { 10819 PetscLogEvent event; 10820 PetscEventPerfInfo eventInfo; 10821 PetscLogDouble cellRate, flopRate; 10822 PetscInt cStart, cEnd, Nf, N; 10823 const char *name; 10824 10825 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10826 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10827 PetscCall(DMGetNumFields(dm, &Nf)); 10828 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10829 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10830 N = (cEnd - cStart) * Nf * eventInfo.count; 10831 flopRate = eventInfo.flops / eventInfo.time; 10832 cellRate = N / eventInfo.time; 10833 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)); 10834 } else { 10835 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."); 10836 } 10837 PetscFunctionReturn(PETSC_SUCCESS); 10838 } 10839