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 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscBool found = PETSC_FALSE; 89 PetscInt Nct, cS = PETSC_INT_MAX, cE = 0; 90 91 PetscFunctionBegin; 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 94 PetscCall(ISGetLocalSize(valueIS, &Nct)); 95 PetscCall(ISGetIndices(valueIS, &ctypes)); 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 found = PETSC_TRUE; 114 } 115 if (!Nct || !found) cS = cE = 0; 116 PetscCall(ISDestroy(&valueIS)); 117 // Reset label for fast lookup 118 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 119 if (cStart) *cStart = cS; 120 if (cEnd) *cEnd = cE; 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 125 { 126 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 127 PetscInt *sStart, *sEnd; 128 PetscViewerVTKFieldType *ft; 129 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 130 DMLabel depthLabel, ctLabel; 131 132 PetscFunctionBegin; 133 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 134 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 135 PetscCall(DMGetCoordinateDim(dm, &cdim)); 136 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 137 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 138 if (field >= 0) { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 140 } else { 141 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 142 } 143 144 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 145 PetscCall(DMPlexGetDepth(dm, &depth)); 146 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 147 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 148 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 149 const DMPolytopeType ict = (DMPolytopeType)c; 150 PetscInt dep; 151 152 if (ict == DM_POLYTOPE_FV_GHOST) continue; 153 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 154 if (pStart >= 0) { 155 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 156 if (dep != depth - cellHeight) continue; 157 } 158 if (field >= 0) { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 160 } else { 161 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 162 } 163 } 164 165 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 166 *types = 0; 167 168 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 169 if (globalvcdof[c]) ++(*types); 170 } 171 172 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 173 t = 0; 174 if (globalvcdof[DM_NUM_POLYTOPES]) { 175 sStart[t] = vStart; 176 sEnd[t] = vEnd; 177 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 178 ++t; 179 } 180 181 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 182 if (globalvcdof[c]) { 183 const DMPolytopeType ict = (DMPolytopeType)c; 184 185 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 186 sStart[t] = cStart; 187 sEnd[t] = cEnd; 188 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 189 ++t; 190 } 191 } 192 193 if (!*types) { 194 if (field >= 0) { 195 const char *fieldname; 196 197 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 199 } else { 200 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 201 } 202 } 203 204 *ssStart = sStart; 205 *ssEnd = sEnd; 206 *sft = ft; 207 PetscFunctionReturn(PETSC_SUCCESS); 208 } 209 210 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 211 { 212 PetscFunctionBegin; 213 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 214 PetscFunctionReturn(PETSC_SUCCESS); 215 } 216 217 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 218 { 219 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 220 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 221 222 PetscFunctionBegin; 223 *ft = PETSC_VTK_INVALID; 224 PetscCall(DMGetCoordinateDim(dm, &cdim)); 225 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 226 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 227 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 228 if (field >= 0) { 229 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 230 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 231 } else { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 234 } 235 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 236 if (globalvcdof[0]) { 237 *sStart = vStart; 238 *sEnd = vEnd; 239 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 240 else *ft = PETSC_VTK_POINT_FIELD; 241 } else if (globalvcdof[1]) { 242 *sStart = cStart; 243 *sEnd = cEnd; 244 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 245 else *ft = PETSC_VTK_CELL_FIELD; 246 } else { 247 if (field >= 0) { 248 const char *fieldname; 249 250 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 251 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 252 } else { 253 PetscCall(PetscInfo(dm, "Could not classify VTK output type of section\n")); 254 } 255 } 256 PetscFunctionReturn(PETSC_SUCCESS); 257 } 258 259 /*@ 260 DMPlexVecView1D - Plot many 1D solutions on the same line graph 261 262 Collective 263 264 Input Parameters: 265 + dm - The `DMPLEX` object 266 . n - The number of vectors 267 . u - The array of local vectors 268 - viewer - The `PetscViewer` 269 270 Level: advanced 271 272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 273 @*/ 274 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 275 { 276 DM cdm; 277 PetscDS ds; 278 PetscDraw draw = NULL; 279 PetscDrawLG lg; 280 Vec coordinates; 281 const PetscScalar *coords, **sol; 282 PetscReal *vals; 283 PetscInt *Nc; 284 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 285 char **names; 286 287 PetscFunctionBegin; 288 PetscCall(DMGetCoordinateDM(dm, &cdm)); 289 PetscCall(DMGetDS(dm, &ds)); 290 PetscCall(PetscDSGetNumFields(ds, &Nf)); 291 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 292 PetscCall(PetscDSGetComponents(ds, &Nc)); 293 294 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 295 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 296 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 297 298 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 299 for (PetscInt i = 0, l = 0; i < n; ++i) { 300 const char *vname; 301 302 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 303 for (PetscInt f = 0; f < Nf; ++f) { 304 PetscObject disc; 305 const char *fname; 306 char tmpname[PETSC_MAX_PATH_LEN]; 307 308 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 309 /* TODO Create names for components */ 310 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 311 PetscCall(PetscObjectGetName(disc, &fname)); 312 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 313 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 314 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 315 PetscCall(PetscStrallocpy(tmpname, &names[l])); 316 } 317 } 318 } 319 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 320 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 321 PetscCall(VecGetArrayRead(coordinates, &coords)); 322 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 323 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 324 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 325 PetscSection s; 326 PetscInt dof; 327 328 PetscCall(DMGetLocalSection(dm, &s)); 329 PetscCall(PetscSectionGetDof(s, eStart, &dof)); 330 if (dof) { 331 // P_2 332 PetscInt vFirst = -1; 333 334 for (PetscInt e = eStart; e < eEnd; ++e) { 335 PetscScalar *xa, *xb, *svals; 336 const PetscInt *cone; 337 338 PetscCall(DMPlexGetCone(dm, e, &cone)); 339 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 340 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 341 if (e == eStart) vFirst = cone[0]; 342 for (PetscInt i = 0; i < n; ++i) { 343 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 344 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 345 } 346 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 347 if (e == eEnd - 1 && cone[1] != vFirst) { 348 for (PetscInt i = 0; i < n; ++i) { 349 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 350 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 351 } 352 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 353 for (PetscInt i = 0; i < n; ++i) { 354 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 355 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 356 } 357 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 358 } 359 } 360 } else { 361 // P_1 362 for (PetscInt v = vStart; v < vEnd; ++v) { 363 PetscScalar *x, *svals; 364 365 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 366 for (PetscInt i = 0; i < n; ++i) { 367 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 368 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 369 } 370 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 371 } 372 } 373 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 374 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 375 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 376 PetscCall(PetscFree3(sol, names, vals)); 377 378 PetscCall(PetscDrawLGDraw(lg)); 379 PetscCall(PetscDrawLGDestroy(&lg)); 380 PetscFunctionReturn(PETSC_SUCCESS); 381 } 382 383 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 384 { 385 DM dm; 386 387 PetscFunctionBegin; 388 PetscCall(VecGetDM(u, &dm)); 389 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 390 PetscFunctionReturn(PETSC_SUCCESS); 391 } 392 393 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 394 { 395 DM dm; 396 PetscSection s; 397 PetscDraw draw, popup; 398 DM cdm; 399 PetscSection coordSection; 400 Vec coordinates; 401 const PetscScalar *array; 402 PetscReal lbound[3], ubound[3]; 403 PetscReal vbound[2], time; 404 PetscBool flg; 405 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 406 const char *name; 407 char title[PETSC_MAX_PATH_LEN]; 408 409 PetscFunctionBegin; 410 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 411 PetscCall(VecGetDM(v, &dm)); 412 PetscCall(DMGetCoordinateDim(dm, &dim)); 413 PetscCall(DMGetLocalSection(dm, &s)); 414 PetscCall(PetscSectionGetNumFields(s, &Nf)); 415 PetscCall(DMGetCoarsenLevel(dm, &level)); 416 PetscCall(DMGetCoordinateDM(dm, &cdm)); 417 PetscCall(DMGetLocalSection(cdm, &coordSection)); 418 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 419 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 420 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 421 422 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 423 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 424 425 PetscCall(VecGetLocalSize(coordinates, &N)); 426 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 427 PetscCall(PetscDrawClear(draw)); 428 429 /* Could implement something like DMDASelectFields() */ 430 for (f = 0; f < Nf; ++f) { 431 DM fdm = dm; 432 Vec fv = v; 433 IS fis; 434 char prefix[PETSC_MAX_PATH_LEN]; 435 const char *fname; 436 437 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 438 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 439 440 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 441 else prefix[0] = '\0'; 442 if (Nf > 1) { 443 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 444 PetscCall(VecGetSubVector(v, fis, &fv)); 445 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 446 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 447 } 448 for (comp = 0; comp < Nc; ++comp, ++w) { 449 PetscInt nmax = 2; 450 451 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 452 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 453 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 454 PetscCall(PetscDrawSetTitle(draw, title)); 455 456 /* TODO Get max and min only for this component */ 457 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 458 if (!flg) { 459 PetscCall(VecMin(fv, NULL, &vbound[0])); 460 PetscCall(VecMax(fv, NULL, &vbound[1])); 461 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 462 } 463 464 PetscCall(PetscDrawGetPopup(draw, &popup)); 465 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 466 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 467 PetscCall(VecGetArrayRead(fv, &array)); 468 for (c = cStart; c < cEnd; ++c) { 469 DMPolytopeType ct; 470 PetscScalar *coords = NULL, *a = NULL; 471 const PetscScalar *coords_arr; 472 PetscBool isDG; 473 PetscInt numCoords; 474 int color[4] = {-1, -1, -1, -1}; 475 476 PetscCall(DMPlexGetCellType(dm, c, &ct)); 477 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 478 if (a) { 479 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 480 color[1] = color[2] = color[3] = color[0]; 481 } else { 482 PetscScalar *vals = NULL; 483 PetscInt numVals, va; 484 485 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 486 if (!numVals) { 487 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 488 continue; 489 } 490 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); 491 switch (numVals / Nc) { 492 case 1: /* P1 Clamped Segment Prism */ 493 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 494 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]); 495 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 496 break; 497 case 3: /* P1 Triangle */ 498 case 4: /* P1 Quadrangle */ 499 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]); 500 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 501 break; 502 case 6: /* P2 Triangle */ 503 case 8: /* P2 Quadrangle */ 504 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]); 505 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 506 break; 507 default: 508 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 509 } 510 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 511 } 512 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 513 switch (numCoords) { 514 case 6: 515 case 12: /* Localized triangle */ 516 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])); 517 break; 518 case 8: 519 case 16: /* Localized quadrilateral */ 520 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 521 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 522 } else { 523 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])); 524 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])); 525 } 526 break; 527 default: 528 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 529 } 530 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 531 } 532 PetscCall(VecRestoreArrayRead(fv, &array)); 533 PetscCall(PetscDrawFlush(draw)); 534 PetscCall(PetscDrawPause(draw)); 535 PetscCall(PetscDrawSave(draw)); 536 } 537 if (Nf > 1) { 538 PetscCall(VecRestoreSubVector(v, fis, &fv)); 539 PetscCall(ISDestroy(&fis)); 540 PetscCall(DMDestroy(&fdm)); 541 } 542 } 543 PetscFunctionReturn(PETSC_SUCCESS); 544 } 545 546 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 547 { 548 DM dm; 549 PetscDraw draw; 550 PetscInt dim; 551 PetscBool isnull; 552 553 PetscFunctionBegin; 554 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 555 PetscCall(PetscDrawIsNull(draw, &isnull)); 556 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 557 558 PetscCall(VecGetDM(v, &dm)); 559 PetscCall(DMGetCoordinateDim(dm, &dim)); 560 switch (dim) { 561 case 1: 562 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 563 break; 564 case 2: 565 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 566 break; 567 default: 568 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 569 } 570 PetscFunctionReturn(PETSC_SUCCESS); 571 } 572 573 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 574 { 575 DM dm; 576 Vec locv; 577 const char *name; 578 PetscSection section; 579 PetscInt pStart, pEnd; 580 PetscInt numFields; 581 PetscViewerVTKFieldType ft; 582 583 PetscFunctionBegin; 584 PetscCall(VecGetDM(v, &dm)); 585 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 586 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 587 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 588 PetscCall(VecCopy(v, locv)); 589 PetscCall(DMGetLocalSection(dm, §ion)); 590 PetscCall(PetscSectionGetNumFields(section, &numFields)); 591 if (!numFields) { 592 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 593 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 594 } else { 595 PetscInt f; 596 597 for (f = 0; f < numFields; f++) { 598 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 599 if (ft == PETSC_VTK_INVALID) continue; 600 PetscCall(PetscObjectReference((PetscObject)locv)); 601 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 602 } 603 PetscCall(VecDestroy(&locv)); 604 } 605 PetscFunctionReturn(PETSC_SUCCESS); 606 } 607 608 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 609 { 610 DM dm; 611 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 612 613 PetscFunctionBegin; 614 PetscCall(VecGetDM(v, &dm)); 615 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 616 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 617 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 618 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 619 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 620 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 621 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 622 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 623 PetscInt i, numFields; 624 PetscObject fe; 625 PetscBool fem = PETSC_FALSE; 626 Vec locv = v; 627 const char *name; 628 PetscInt step; 629 PetscReal time; 630 631 PetscCall(DMGetNumFields(dm, &numFields)); 632 for (i = 0; i < numFields; i++) { 633 PetscCall(DMGetField(dm, i, NULL, &fe)); 634 if (fe->classid == PETSCFE_CLASSID) { 635 fem = PETSC_TRUE; 636 break; 637 } 638 } 639 if (fem) { 640 PetscObject isZero; 641 642 PetscCall(DMGetLocalVector(dm, &locv)); 643 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 644 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 645 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 646 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 647 PetscCall(VecCopy(v, locv)); 648 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 649 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 650 } 651 if (isvtk) { 652 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 653 } else if (ishdf5) { 654 #if defined(PETSC_HAVE_HDF5) 655 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 656 #else 657 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 658 #endif 659 } else if (isdraw) { 660 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 661 } else if (ispython) { 662 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 663 } else if (isglvis) { 664 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 665 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 666 PetscCall(VecView_GLVis(locv, viewer)); 667 } else if (iscgns) { 668 #if defined(PETSC_HAVE_CGNS) 669 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 670 #else 671 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 672 #endif 673 } 674 if (fem) { 675 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 676 PetscCall(DMRestoreLocalVector(dm, &locv)); 677 } 678 } else { 679 PetscBool isseq; 680 681 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 682 if (isseq) PetscCall(VecView_Seq(v, viewer)); 683 else PetscCall(VecView_MPI(v, viewer)); 684 } 685 PetscFunctionReturn(PETSC_SUCCESS); 686 } 687 688 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 689 { 690 DM dm; 691 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 692 693 PetscFunctionBegin; 694 PetscCall(VecGetDM(v, &dm)); 695 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 696 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 697 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 698 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 699 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 700 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 701 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 702 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 703 if (isvtk || isdraw || isglvis || iscgns || ispython) { 704 Vec locv; 705 PetscObject isZero; 706 const char *name; 707 708 PetscCall(DMGetLocalVector(dm, &locv)); 709 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 710 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 711 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 712 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 713 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 714 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 715 PetscCall(VecView_Plex_Local(locv, viewer)); 716 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 717 PetscCall(DMRestoreLocalVector(dm, &locv)); 718 } else if (ishdf5) { 719 #if defined(PETSC_HAVE_HDF5) 720 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 721 #else 722 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 723 #endif 724 } else if (isexodusii) { 725 #if defined(PETSC_HAVE_EXODUSII) 726 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 727 #else 728 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 729 #endif 730 } else { 731 PetscBool isseq; 732 733 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 734 if (isseq) PetscCall(VecView_Seq(v, viewer)); 735 else PetscCall(VecView_MPI(v, viewer)); 736 } 737 PetscFunctionReturn(PETSC_SUCCESS); 738 } 739 740 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 741 { 742 DM dm; 743 MPI_Comm comm; 744 PetscViewerFormat format; 745 Vec v; 746 PetscBool isvtk, ishdf5; 747 748 PetscFunctionBegin; 749 PetscCall(VecGetDM(originalv, &dm)); 750 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 751 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 752 PetscCall(PetscViewerGetFormat(viewer, &format)); 753 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 754 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 755 if (format == PETSC_VIEWER_NATIVE) { 756 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 757 /* this need a better fix */ 758 if (dm->useNatural) { 759 if (dm->sfNatural) { 760 const char *vecname; 761 PetscInt n, nroots; 762 763 PetscCall(VecGetLocalSize(originalv, &n)); 764 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 765 if (n == nroots) { 766 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 767 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 768 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 769 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 770 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 771 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 772 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 773 } else v = originalv; 774 } else v = originalv; 775 776 if (ishdf5) { 777 #if defined(PETSC_HAVE_HDF5) 778 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 779 #else 780 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 781 #endif 782 } else if (isvtk) { 783 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 784 } else { 785 PetscBool isseq; 786 787 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 788 if (isseq) PetscCall(VecView_Seq(v, viewer)); 789 else PetscCall(VecView_MPI(v, viewer)); 790 } 791 if (v != originalv) PetscCall(VecDestroy(&v)); 792 PetscFunctionReturn(PETSC_SUCCESS); 793 } 794 795 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 796 { 797 DM dm; 798 PetscBool ishdf5; 799 800 PetscFunctionBegin; 801 PetscCall(VecGetDM(v, &dm)); 802 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 803 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 804 if (ishdf5) { 805 DM dmBC; 806 Vec gv; 807 const char *name; 808 809 PetscCall(DMGetOutputDM(dm, &dmBC)); 810 PetscCall(DMGetGlobalVector(dmBC, &gv)); 811 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 812 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 813 PetscCall(VecLoad_Default(gv, viewer)); 814 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 815 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 816 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 817 } else PetscCall(VecLoad_Default(v, viewer)); 818 PetscFunctionReturn(PETSC_SUCCESS); 819 } 820 821 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 822 { 823 DM dm; 824 PetscBool ishdf5, isexodusii, iscgns; 825 826 PetscFunctionBegin; 827 PetscCall(VecGetDM(v, &dm)); 828 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 829 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 830 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 831 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 832 if (ishdf5) { 833 #if defined(PETSC_HAVE_HDF5) 834 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 835 #else 836 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 837 #endif 838 } else if (isexodusii) { 839 #if defined(PETSC_HAVE_EXODUSII) 840 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 841 #else 842 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 843 #endif 844 } else if (iscgns) { 845 #if defined(PETSC_HAVE_CGNS) 846 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 847 #else 848 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 849 #endif 850 } else PetscCall(VecLoad_Default(v, viewer)); 851 PetscFunctionReturn(PETSC_SUCCESS); 852 } 853 854 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 855 { 856 DM dm; 857 PetscViewerFormat format; 858 PetscBool ishdf5; 859 860 PetscFunctionBegin; 861 PetscCall(VecGetDM(originalv, &dm)); 862 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 863 PetscCall(PetscViewerGetFormat(viewer, &format)); 864 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 865 if (format == PETSC_VIEWER_NATIVE) { 866 if (dm->useNatural) { 867 if (dm->sfNatural) { 868 if (ishdf5) { 869 #if defined(PETSC_HAVE_HDF5) 870 Vec v; 871 const char *vecname; 872 873 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 874 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 875 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 876 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 877 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 878 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 879 PetscCall(VecDestroy(&v)); 880 #else 881 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 882 #endif 883 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 884 } 885 } else PetscCall(VecLoad_Default(originalv, viewer)); 886 } 887 PetscFunctionReturn(PETSC_SUCCESS); 888 } 889 890 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 891 { 892 PetscSection coordSection; 893 Vec coordinates; 894 DMLabel depthLabel, celltypeLabel; 895 const char *name[4]; 896 const PetscScalar *a; 897 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 898 899 PetscFunctionBegin; 900 PetscCall(DMGetDimension(dm, &dim)); 901 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 902 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 903 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 904 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 905 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 906 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 907 PetscCall(VecGetArrayRead(coordinates, &a)); 908 name[0] = "vertex"; 909 name[1] = "edge"; 910 name[dim - 1] = "face"; 911 name[dim] = "cell"; 912 for (c = cStart; c < cEnd; ++c) { 913 PetscInt *closure = NULL; 914 PetscInt closureSize, cl, ct; 915 916 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 917 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 918 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 919 PetscCall(PetscViewerASCIIPushTab(viewer)); 920 for (cl = 0; cl < closureSize * 2; cl += 2) { 921 PetscInt point = closure[cl], depth, dof, off, d, p; 922 923 if ((point < pStart) || (point >= pEnd)) continue; 924 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 925 if (!dof) continue; 926 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 927 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 928 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 929 for (p = 0; p < dof / dim; ++p) { 930 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 931 for (d = 0; d < dim; ++d) { 932 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 933 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 934 } 935 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 936 } 937 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 938 } 939 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 940 PetscCall(PetscViewerASCIIPopTab(viewer)); 941 } 942 PetscCall(VecRestoreArrayRead(coordinates, &a)); 943 PetscFunctionReturn(PETSC_SUCCESS); 944 } 945 946 typedef enum { 947 CS_CARTESIAN, 948 CS_POLAR, 949 CS_CYLINDRICAL, 950 CS_SPHERICAL 951 } CoordSystem; 952 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 953 954 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 955 { 956 PetscInt i; 957 958 PetscFunctionBegin; 959 if (dim > 3) { 960 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 961 } else { 962 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 963 964 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 965 switch (cs) { 966 case CS_CARTESIAN: 967 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 968 break; 969 case CS_POLAR: 970 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 971 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 972 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 973 break; 974 case CS_CYLINDRICAL: 975 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 976 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 977 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 978 trcoords[2] = coords[2]; 979 break; 980 case CS_SPHERICAL: 981 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 982 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 983 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 984 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 985 break; 986 } 987 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 988 } 989 PetscFunctionReturn(PETSC_SUCCESS); 990 } 991 992 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 993 { 994 DM_Plex *mesh = (DM_Plex *)dm->data; 995 DM cdm, cdmCell; 996 PetscSection coordSection, coordSectionCell; 997 Vec coordinates, coordinatesCell; 998 PetscViewerFormat format; 999 1000 PetscFunctionBegin; 1001 PetscCall(PetscViewerGetFormat(viewer, &format)); 1002 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1003 const char *name; 1004 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1005 PetscInt pStart, pEnd, p, numLabels, l; 1006 PetscMPIInt rank, size; 1007 1008 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1009 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1010 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1011 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1012 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1013 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1014 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1015 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1016 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1017 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1018 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1019 PetscCall(DMGetDimension(dm, &dim)); 1020 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1021 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1022 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1023 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1025 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1026 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1027 for (p = pStart; p < pEnd; ++p) { 1028 PetscInt dof, off, s; 1029 1030 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1031 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1032 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1033 } 1034 PetscCall(PetscViewerFlush(viewer)); 1035 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1036 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1037 for (p = pStart; p < pEnd; ++p) { 1038 PetscInt dof, off, c; 1039 1040 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1041 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1042 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])); 1043 } 1044 PetscCall(PetscViewerFlush(viewer)); 1045 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1046 if (coordSection && coordinates) { 1047 CoordSystem cs = CS_CARTESIAN; 1048 const PetscScalar *array, *arrayCell = NULL; 1049 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1050 PetscMPIInt rank; 1051 const char *name; 1052 1053 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1054 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1055 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1056 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1057 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1058 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1059 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1060 pStart = PetscMin(pvStart, pcStart); 1061 pEnd = PetscMax(pvEnd, pcEnd); 1062 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1063 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1064 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1065 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1066 1067 PetscCall(VecGetArrayRead(coordinates, &array)); 1068 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1069 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1070 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1071 for (p = pStart; p < pEnd; ++p) { 1072 PetscInt dof, off; 1073 1074 if (p >= pvStart && p < pvEnd) { 1075 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1076 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1077 if (dof) { 1078 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1079 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1080 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1081 } 1082 } 1083 if (cdmCell && p >= pcStart && p < pcEnd) { 1084 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1085 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1086 if (dof) { 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1088 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1089 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1090 } 1091 } 1092 } 1093 PetscCall(PetscViewerFlush(viewer)); 1094 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1095 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1096 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1097 } 1098 PetscCall(DMGetNumLabels(dm, &numLabels)); 1099 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1100 for (l = 0; l < numLabels; ++l) { 1101 DMLabel label; 1102 PetscBool isdepth; 1103 const char *name; 1104 1105 PetscCall(DMGetLabelName(dm, l, &name)); 1106 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1107 if (isdepth) continue; 1108 PetscCall(DMGetLabel(dm, name, &label)); 1109 PetscCall(DMLabelView(label, viewer)); 1110 } 1111 if (size > 1) { 1112 PetscSF sf; 1113 1114 PetscCall(DMGetPointSF(dm, &sf)); 1115 PetscCall(PetscSFView(sf, viewer)); 1116 } 1117 if (mesh->periodic.face_sfs) 1118 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1119 PetscCall(PetscViewerFlush(viewer)); 1120 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1121 const char *name, *color; 1122 const char *defcolors[3] = {"gray", "orange", "green"}; 1123 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1124 char lname[PETSC_MAX_PATH_LEN]; 1125 PetscReal scale = 2.0; 1126 PetscReal tikzscale = 1.0; 1127 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1128 double tcoords[3]; 1129 PetscScalar *coords; 1130 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; 1131 PetscMPIInt rank, size; 1132 char **names, **colors, **lcolors; 1133 PetscBool flg, lflg; 1134 PetscBT wp = NULL; 1135 PetscInt pEnd, pStart; 1136 1137 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1138 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1139 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1140 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1141 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1142 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1143 PetscCall(DMGetDimension(dm, &dim)); 1144 PetscCall(DMPlexGetDepth(dm, &depth)); 1145 PetscCall(DMGetNumLabels(dm, &numLabels)); 1146 numLabels = PetscMax(numLabels, 10); 1147 numColors = 10; 1148 numLColors = 10; 1149 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1150 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1151 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1152 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1153 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1154 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1155 n = 4; 1156 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1157 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1158 n = 4; 1159 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1160 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1161 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1162 if (!useLabels) numLabels = 0; 1163 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1164 if (!useColors) { 1165 numColors = 3; 1166 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1167 } 1168 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1169 if (!useColors) { 1170 numLColors = 4; 1171 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1172 } 1173 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1174 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1175 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1176 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1177 if (depth < dim) plotEdges = PETSC_FALSE; 1178 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1179 1180 /* filter points with labelvalue != labeldefaultvalue */ 1181 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1182 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1183 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1184 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1185 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1186 if (lflg) { 1187 DMLabel lbl; 1188 1189 PetscCall(DMGetLabel(dm, lname, &lbl)); 1190 if (lbl) { 1191 PetscInt val, defval; 1192 1193 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1194 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1195 for (c = pStart; c < pEnd; c++) { 1196 PetscInt *closure = NULL; 1197 PetscInt closureSize; 1198 1199 PetscCall(DMLabelGetValue(lbl, c, &val)); 1200 if (val == defval) continue; 1201 1202 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1203 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1204 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1205 } 1206 } 1207 } 1208 1209 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1210 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1211 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1212 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1213 \\documentclass[tikz]{standalone}\n\n\ 1214 \\usepackage{pgflibraryshapes}\n\ 1215 \\usetikzlibrary{backgrounds}\n\ 1216 \\usetikzlibrary{arrows}\n\ 1217 \\begin{document}\n")); 1218 if (size > 1) { 1219 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1220 for (p = 0; p < size; ++p) { 1221 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1222 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1223 } 1224 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1225 } 1226 if (drawHasse) { 1227 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1228 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1234 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1235 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1236 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1237 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1238 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1242 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1244 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1245 } 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1247 1248 /* Plot vertices */ 1249 PetscCall(VecGetArray(coordinates, &coords)); 1250 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1251 for (v = vStart; v < vEnd; ++v) { 1252 PetscInt off, dof, d; 1253 PetscBool isLabeled = PETSC_FALSE; 1254 1255 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1256 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1257 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1258 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1259 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1260 for (d = 0; d < dof; ++d) { 1261 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1262 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1263 } 1264 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1265 if (dim == 3) { 1266 PetscReal tmp = tcoords[1]; 1267 tcoords[1] = tcoords[2]; 1268 tcoords[2] = -tmp; 1269 } 1270 for (d = 0; d < dof; ++d) { 1271 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1272 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1273 } 1274 if (drawHasse) color = colors[0 % numColors]; 1275 else color = colors[rank % numColors]; 1276 for (l = 0; l < numLabels; ++l) { 1277 PetscInt val; 1278 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1279 if (val >= 0) { 1280 color = lcolors[l % numLColors]; 1281 isLabeled = PETSC_TRUE; 1282 break; 1283 } 1284 } 1285 if (drawNumbers[0]) { 1286 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1287 } else if (drawColors[0]) { 1288 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1289 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1290 } 1291 PetscCall(VecRestoreArray(coordinates, &coords)); 1292 PetscCall(PetscViewerFlush(viewer)); 1293 /* Plot edges */ 1294 if (plotEdges) { 1295 PetscCall(VecGetArray(coordinates, &coords)); 1296 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1297 for (e = eStart; e < eEnd; ++e) { 1298 const PetscInt *cone; 1299 PetscInt coneSize, offA, offB, dof, d; 1300 1301 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1302 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1303 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1304 PetscCall(DMPlexGetCone(dm, e, &cone)); 1305 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1306 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1307 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1308 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1309 for (d = 0; d < dof; ++d) { 1310 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1311 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1312 } 1313 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1314 if (dim == 3) { 1315 PetscReal tmp = tcoords[1]; 1316 tcoords[1] = tcoords[2]; 1317 tcoords[2] = -tmp; 1318 } 1319 for (d = 0; d < dof; ++d) { 1320 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1321 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1322 } 1323 if (drawHasse) color = colors[1 % numColors]; 1324 else color = colors[rank % numColors]; 1325 for (l = 0; l < numLabels; ++l) { 1326 PetscInt val; 1327 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1328 if (val >= 0) { 1329 color = lcolors[l % numLColors]; 1330 break; 1331 } 1332 } 1333 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1334 } 1335 PetscCall(VecRestoreArray(coordinates, &coords)); 1336 PetscCall(PetscViewerFlush(viewer)); 1337 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1338 } 1339 /* Plot cells */ 1340 if (dim == 3 || !drawNumbers[1]) { 1341 for (e = eStart; e < eEnd; ++e) { 1342 const PetscInt *cone; 1343 1344 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1345 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(DMPlexGetCone(dm, e, &cone)); 1355 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1356 } 1357 } else { 1358 DMPolytopeType ct; 1359 1360 /* Drawing a 2D polygon */ 1361 for (c = cStart; c < cEnd; ++c) { 1362 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1363 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1364 if (DMPolytopeTypeIsHybrid(ct)) { 1365 const PetscInt *cone; 1366 PetscInt coneSize, e; 1367 1368 PetscCall(DMPlexGetCone(dm, c, &cone)); 1369 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1370 for (e = 0; e < coneSize; ++e) { 1371 const PetscInt *econe; 1372 1373 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1374 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)); 1375 } 1376 } else { 1377 PetscInt *closure = NULL; 1378 PetscInt closureSize, Nv = 0, v; 1379 1380 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1381 for (p = 0; p < closureSize * 2; p += 2) { 1382 const PetscInt point = closure[p]; 1383 1384 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1385 } 1386 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1387 for (v = 0; v <= Nv; ++v) { 1388 const PetscInt vertex = closure[v % Nv]; 1389 1390 if (v > 0) { 1391 if (plotEdges) { 1392 const PetscInt *edge; 1393 PetscInt endpoints[2], ne; 1394 1395 endpoints[0] = closure[v - 1]; 1396 endpoints[1] = vertex; 1397 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1398 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1399 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1400 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1401 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1402 } 1403 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1404 } 1405 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1406 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1407 } 1408 } 1409 } 1410 for (c = cStart; c < cEnd; ++c) { 1411 double ccoords[3] = {0.0, 0.0, 0.0}; 1412 PetscBool isLabeled = PETSC_FALSE; 1413 PetscScalar *cellCoords = NULL; 1414 const PetscScalar *array; 1415 PetscInt numCoords, cdim, d; 1416 PetscBool isDG; 1417 1418 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1419 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1420 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1421 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1422 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1423 for (p = 0; p < numCoords / cdim; ++p) { 1424 for (d = 0; d < cdim; ++d) { 1425 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1426 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1427 } 1428 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1429 if (cdim == 3) { 1430 PetscReal tmp = tcoords[1]; 1431 tcoords[1] = tcoords[2]; 1432 tcoords[2] = -tmp; 1433 } 1434 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1435 } 1436 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1437 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1438 for (d = 0; d < cdim; ++d) { 1439 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1440 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1441 } 1442 if (drawHasse) color = colors[depth % numColors]; 1443 else color = colors[rank % numColors]; 1444 for (l = 0; l < numLabels; ++l) { 1445 PetscInt val; 1446 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1447 if (val >= 0) { 1448 color = lcolors[l % numLColors]; 1449 isLabeled = PETSC_TRUE; 1450 break; 1451 } 1452 } 1453 if (drawNumbers[dim]) { 1454 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1455 } else if (drawColors[dim]) { 1456 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1457 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1458 } 1459 if (drawHasse) { 1460 int height = 0; 1461 1462 color = colors[depth % numColors]; 1463 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1464 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1465 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1466 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1467 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1468 1469 if (depth > 2) { 1470 color = colors[1 % numColors]; 1471 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1472 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1473 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1474 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1475 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1476 } 1477 1478 color = colors[1 % numColors]; 1479 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1480 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1481 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1482 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1483 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1484 1485 color = colors[0 % numColors]; 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1489 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1490 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1491 1492 for (p = pStart; p < pEnd; ++p) { 1493 const PetscInt *cone; 1494 PetscInt coneSize, cp; 1495 1496 PetscCall(DMPlexGetCone(dm, p, &cone)); 1497 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1498 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1499 } 1500 } 1501 PetscCall(PetscViewerFlush(viewer)); 1502 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1505 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1506 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1507 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1508 PetscCall(PetscFree3(names, colors, lcolors)); 1509 PetscCall(PetscBTDestroy(&wp)); 1510 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1511 Vec cown, acown; 1512 VecScatter sct; 1513 ISLocalToGlobalMapping g2l; 1514 IS gid, acis; 1515 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1516 MPI_Group ggroup, ngroup; 1517 PetscScalar *array, nid; 1518 const PetscInt *idxs; 1519 PetscInt *idxs2, *start, *adjacency, *work; 1520 PetscInt64 lm[3], gm[3]; 1521 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1522 PetscMPIInt d1, d2, rank; 1523 1524 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1525 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1526 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1527 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1528 #endif 1529 if (ncomm != MPI_COMM_NULL) { 1530 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1531 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1532 d1 = 0; 1533 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1534 nid = d2; 1535 PetscCallMPI(MPI_Group_free(&ggroup)); 1536 PetscCallMPI(MPI_Group_free(&ngroup)); 1537 PetscCallMPI(MPI_Comm_free(&ncomm)); 1538 } else nid = 0.0; 1539 1540 /* Get connectivity */ 1541 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1542 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1543 1544 /* filter overlapped local cells */ 1545 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1546 PetscCall(ISGetIndices(gid, &idxs)); 1547 PetscCall(ISGetLocalSize(gid, &cum)); 1548 PetscCall(PetscMalloc1(cum, &idxs2)); 1549 for (c = cStart, cum = 0; c < cEnd; c++) { 1550 if (idxs[c - cStart] < 0) continue; 1551 idxs2[cum++] = idxs[c - cStart]; 1552 } 1553 PetscCall(ISRestoreIndices(gid, &idxs)); 1554 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1555 PetscCall(ISDestroy(&gid)); 1556 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1557 1558 /* support for node-aware cell locality */ 1559 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1560 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1561 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1562 PetscCall(VecGetArray(cown, &array)); 1563 for (c = 0; c < numVertices; c++) array[c] = nid; 1564 PetscCall(VecRestoreArray(cown, &array)); 1565 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1566 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1567 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1568 PetscCall(ISDestroy(&acis)); 1569 PetscCall(VecScatterDestroy(&sct)); 1570 PetscCall(VecDestroy(&cown)); 1571 1572 /* compute edgeCut */ 1573 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1574 PetscCall(PetscMalloc1(cum, &work)); 1575 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1576 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1577 PetscCall(ISDestroy(&gid)); 1578 PetscCall(VecGetArray(acown, &array)); 1579 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1580 PetscInt totl; 1581 1582 totl = start[c + 1] - start[c]; 1583 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1584 for (i = 0; i < totl; i++) { 1585 if (work[i] < 0) { 1586 ect += 1; 1587 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1588 } 1589 } 1590 } 1591 PetscCall(PetscFree(work)); 1592 PetscCall(VecRestoreArray(acown, &array)); 1593 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1594 lm[1] = -numVertices; 1595 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1596 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1597 lm[0] = ect; /* edgeCut */ 1598 lm[1] = ectn; /* node-aware edgeCut */ 1599 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1600 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1601 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1602 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1603 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1604 #else 1605 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1606 #endif 1607 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1608 PetscCall(PetscFree(start)); 1609 PetscCall(PetscFree(adjacency)); 1610 PetscCall(VecDestroy(&acown)); 1611 } else { 1612 const char *name; 1613 PetscInt *sizes, *hybsizes, *ghostsizes; 1614 PetscInt locDepth, depth, cellHeight, dim, d; 1615 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1616 PetscInt numLabels, l, maxSize = 17; 1617 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1618 MPI_Comm comm; 1619 PetscMPIInt size, rank; 1620 1621 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1622 PetscCallMPI(MPI_Comm_size(comm, &size)); 1623 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1624 PetscCall(DMGetDimension(dm, &dim)); 1625 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1626 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1627 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1628 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1629 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1630 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1631 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1632 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1633 gcNum = gcEnd - gcStart; 1634 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1635 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1636 for (d = 0; d <= depth; d++) { 1637 PetscInt Nc[2] = {0, 0}, ict; 1638 1639 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1640 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1641 ict = ct0; 1642 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1643 ct0 = (DMPolytopeType)ict; 1644 for (p = pStart; p < pEnd; ++p) { 1645 DMPolytopeType ct; 1646 1647 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1648 if (ct == ct0) ++Nc[0]; 1649 else ++Nc[1]; 1650 } 1651 if (size < maxSize) { 1652 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1653 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1654 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1655 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1656 for (p = 0; p < size; ++p) { 1657 if (rank == 0) { 1658 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1659 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1660 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1661 } 1662 } 1663 } else { 1664 PetscInt locMinMax[2]; 1665 1666 locMinMax[0] = Nc[0] + Nc[1]; 1667 locMinMax[1] = Nc[0] + Nc[1]; 1668 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1669 locMinMax[0] = Nc[1]; 1670 locMinMax[1] = Nc[1]; 1671 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1672 if (d == depth) { 1673 locMinMax[0] = gcNum; 1674 locMinMax[1] = gcNum; 1675 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1676 } 1677 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1678 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1679 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1680 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1681 } 1682 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1683 } 1684 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1685 { 1686 const PetscReal *maxCell; 1687 const PetscReal *L; 1688 PetscBool localized; 1689 1690 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1691 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1692 if (L || localized) { 1693 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1694 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1695 if (L) { 1696 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1697 for (d = 0; d < dim; ++d) { 1698 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1699 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1700 } 1701 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1702 } 1703 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1704 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1705 } 1706 } 1707 PetscCall(DMGetNumLabels(dm, &numLabels)); 1708 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1709 for (l = 0; l < numLabels; ++l) { 1710 DMLabel label; 1711 const char *name; 1712 PetscInt *values; 1713 PetscInt numValues, v; 1714 1715 PetscCall(DMGetLabelName(dm, l, &name)); 1716 PetscCall(DMGetLabel(dm, name, &label)); 1717 PetscCall(DMLabelGetNumValues(label, &numValues)); 1718 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1719 1720 { // Extract array of DMLabel values so it can be sorted 1721 IS is_values; 1722 const PetscInt *is_values_local = NULL; 1723 1724 PetscCall(DMLabelGetValueIS(label, &is_values)); 1725 PetscCall(ISGetIndices(is_values, &is_values_local)); 1726 PetscCall(PetscMalloc1(numValues, &values)); 1727 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1728 PetscCall(PetscSortInt(numValues, values)); 1729 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1730 PetscCall(ISDestroy(&is_values)); 1731 } 1732 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1733 for (v = 0; v < numValues; ++v) { 1734 PetscInt size; 1735 1736 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1737 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1738 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1739 } 1740 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1741 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1742 PetscCall(PetscFree(values)); 1743 } 1744 { 1745 char **labelNames; 1746 PetscInt Nl = numLabels; 1747 PetscBool flg; 1748 1749 PetscCall(PetscMalloc1(Nl, &labelNames)); 1750 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1751 for (l = 0; l < Nl; ++l) { 1752 DMLabel label; 1753 1754 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1755 if (flg) { 1756 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1757 PetscCall(DMLabelView(label, viewer)); 1758 } 1759 PetscCall(PetscFree(labelNames[l])); 1760 } 1761 PetscCall(PetscFree(labelNames)); 1762 } 1763 /* If no fields are specified, people do not want to see adjacency */ 1764 if (dm->Nf) { 1765 PetscInt f; 1766 1767 for (f = 0; f < dm->Nf; ++f) { 1768 const char *name; 1769 1770 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1771 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1772 PetscCall(PetscViewerASCIIPushTab(viewer)); 1773 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1774 if (dm->fields[f].adjacency[0]) { 1775 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1776 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1777 } else { 1778 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1779 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1780 } 1781 PetscCall(PetscViewerASCIIPopTab(viewer)); 1782 } 1783 } 1784 PetscCall(DMGetCoarseDM(dm, &cdm)); 1785 if (cdm) { 1786 PetscCall(PetscViewerASCIIPushTab(viewer)); 1787 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1788 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1789 PetscCall(PetscViewerASCIIPopTab(viewer)); 1790 } 1791 } 1792 PetscFunctionReturn(PETSC_SUCCESS); 1793 } 1794 1795 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1796 { 1797 DMPolytopeType ct; 1798 PetscMPIInt rank; 1799 PetscInt cdim; 1800 1801 PetscFunctionBegin; 1802 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1803 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1804 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1805 switch (ct) { 1806 case DM_POLYTOPE_SEGMENT: 1807 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1808 switch (cdim) { 1809 case 1: { 1810 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1811 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1812 1813 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1814 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1815 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1816 } break; 1817 case 2: { 1818 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1819 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1820 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1821 1822 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1823 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1824 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1825 } break; 1826 default: 1827 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1828 } 1829 break; 1830 case DM_POLYTOPE_TRIANGLE: 1831 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1832 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1833 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1834 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1835 break; 1836 case DM_POLYTOPE_QUADRILATERAL: 1837 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1838 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1839 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1840 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1841 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1842 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1843 break; 1844 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1845 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1846 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1847 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1848 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1849 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1850 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1851 break; 1852 case DM_POLYTOPE_FV_GHOST: 1853 break; 1854 default: 1855 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1856 } 1857 PetscFunctionReturn(PETSC_SUCCESS); 1858 } 1859 1860 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1861 { 1862 PetscReal centroid[2] = {0., 0.}; 1863 PetscMPIInt rank; 1864 PetscMPIInt fillColor; 1865 1866 PetscFunctionBegin; 1867 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1868 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1869 for (PetscInt v = 0; v < Nv; ++v) { 1870 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1871 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1872 } 1873 for (PetscInt e = 0; e < Nv; ++e) { 1874 refCoords[0] = refVertices[e * 2 + 0]; 1875 refCoords[1] = refVertices[e * 2 + 1]; 1876 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1877 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1878 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1879 } 1880 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1881 for (PetscInt d = 0; d < edgeDiv; ++d) { 1882 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)); 1883 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1884 } 1885 } 1886 PetscFunctionReturn(PETSC_SUCCESS); 1887 } 1888 1889 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1890 { 1891 DMPolytopeType ct; 1892 1893 PetscFunctionBegin; 1894 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1895 switch (ct) { 1896 case DM_POLYTOPE_TRIANGLE: { 1897 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1898 1899 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1900 } break; 1901 case DM_POLYTOPE_QUADRILATERAL: { 1902 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1903 1904 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1905 } break; 1906 default: 1907 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1908 } 1909 PetscFunctionReturn(PETSC_SUCCESS); 1910 } 1911 1912 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1913 { 1914 PetscDraw draw; 1915 DM cdm; 1916 PetscSection coordSection; 1917 Vec coordinates; 1918 PetscReal xyl[3], xyr[3]; 1919 PetscReal *refCoords, *edgeCoords; 1920 PetscBool isnull, drawAffine; 1921 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1922 1923 PetscFunctionBegin; 1924 PetscCall(DMGetCoordinateDim(dm, &dim)); 1925 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1926 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1927 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1928 edgeDiv = cDegree + 1; 1929 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1930 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1931 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1932 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1933 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1934 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1935 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1936 1937 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1938 PetscCall(PetscDrawIsNull(draw, &isnull)); 1939 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1940 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1941 1942 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1943 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1944 PetscCall(PetscDrawClear(draw)); 1945 1946 for (c = cStart; c < cEnd; ++c) { 1947 PetscScalar *coords = NULL; 1948 const PetscScalar *coords_arr; 1949 PetscInt numCoords; 1950 PetscBool isDG; 1951 1952 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1953 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1954 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1955 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1956 } 1957 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1958 PetscCall(PetscDrawFlush(draw)); 1959 PetscCall(PetscDrawPause(draw)); 1960 PetscCall(PetscDrawSave(draw)); 1961 PetscFunctionReturn(PETSC_SUCCESS); 1962 } 1963 1964 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1965 { 1966 DM odm = dm, rdm = dm, cdm; 1967 PetscFE fe; 1968 PetscSpace sp; 1969 PetscClassId id; 1970 PetscInt degree; 1971 PetscBool hoView = PETSC_TRUE; 1972 1973 PetscFunctionBegin; 1974 PetscObjectOptionsBegin((PetscObject)dm); 1975 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1976 PetscOptionsEnd(); 1977 PetscCall(PetscObjectReference((PetscObject)dm)); 1978 *hdm = dm; 1979 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1980 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1981 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1982 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1983 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1984 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1985 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1986 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1987 DM cdm, rcdm; 1988 Mat In; 1989 Vec cl, rcl; 1990 1991 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1992 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1993 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1994 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1995 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1996 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1997 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1998 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1999 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2000 PetscCall(MatMult(In, cl, rcl)); 2001 PetscCall(MatDestroy(&In)); 2002 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2003 PetscCall(DMDestroy(&odm)); 2004 odm = rdm; 2005 } 2006 *hdm = rdm; 2007 PetscFunctionReturn(PETSC_SUCCESS); 2008 } 2009 2010 #if defined(PETSC_HAVE_EXODUSII) 2011 #include <exodusII.h> 2012 #include <petscviewerexodusii.h> 2013 #endif 2014 2015 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2016 { 2017 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2018 char name[PETSC_MAX_PATH_LEN]; 2019 2020 PetscFunctionBegin; 2021 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2022 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2023 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2024 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2025 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2026 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2027 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2028 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2029 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2030 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2031 if (iascii) { 2032 PetscViewerFormat format; 2033 PetscCall(PetscViewerGetFormat(viewer, &format)); 2034 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2035 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2036 } else if (ishdf5) { 2037 #if defined(PETSC_HAVE_HDF5) 2038 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2039 #else 2040 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2041 #endif 2042 } else if (isvtk) { 2043 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2044 } else if (isdraw) { 2045 DM hdm; 2046 2047 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2048 PetscCall(DMPlexView_Draw(hdm, viewer)); 2049 PetscCall(DMDestroy(&hdm)); 2050 } else if (isglvis) { 2051 PetscCall(DMPlexView_GLVis(dm, viewer)); 2052 #if defined(PETSC_HAVE_EXODUSII) 2053 } else if (isexodus) { 2054 /* 2055 exodusII requires that all sets be part of exactly one cell set. 2056 If the dm does not have a "Cell Sets" label defined, we create one 2057 with ID 1, containing all cells. 2058 Note that if the Cell Sets label is defined but does not cover all cells, 2059 we may still have a problem. This should probably be checked here or in the viewer; 2060 */ 2061 PetscInt numCS; 2062 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2063 if (!numCS) { 2064 PetscInt cStart, cEnd, c; 2065 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2066 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2067 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2068 } 2069 PetscCall(DMView_PlexExodusII(dm, viewer)); 2070 #endif 2071 #if defined(PETSC_HAVE_CGNS) 2072 } else if (iscgns) { 2073 PetscCall(DMView_PlexCGNS(dm, viewer)); 2074 #endif 2075 } else if (ispython) { 2076 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2077 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2078 /* Optionally view the partition */ 2079 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2080 if (flg) { 2081 Vec ranks; 2082 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2083 PetscCall(VecView(ranks, viewer)); 2084 PetscCall(VecDestroy(&ranks)); 2085 } 2086 /* Optionally view a label */ 2087 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2088 if (flg) { 2089 DMLabel label; 2090 Vec val; 2091 2092 PetscCall(DMGetLabel(dm, name, &label)); 2093 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2094 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2095 PetscCall(VecView(val, viewer)); 2096 PetscCall(VecDestroy(&val)); 2097 } 2098 PetscFunctionReturn(PETSC_SUCCESS); 2099 } 2100 2101 /*@ 2102 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2103 2104 Collective 2105 2106 Input Parameters: 2107 + dm - The `DM` whose topology is to be saved 2108 - viewer - The `PetscViewer` to save it in 2109 2110 Level: advanced 2111 2112 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2113 @*/ 2114 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2115 { 2116 PetscBool ishdf5; 2117 2118 PetscFunctionBegin; 2119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2120 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2121 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2122 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2123 if (ishdf5) { 2124 #if defined(PETSC_HAVE_HDF5) 2125 PetscViewerFormat format; 2126 PetscCall(PetscViewerGetFormat(viewer, &format)); 2127 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2128 IS globalPointNumbering; 2129 2130 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2131 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2132 PetscCall(ISDestroy(&globalPointNumbering)); 2133 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2134 #else 2135 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2136 #endif 2137 } 2138 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2139 PetscFunctionReturn(PETSC_SUCCESS); 2140 } 2141 2142 /*@ 2143 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2144 2145 Collective 2146 2147 Input Parameters: 2148 + dm - The `DM` whose coordinates are to be saved 2149 - viewer - The `PetscViewer` for saving 2150 2151 Level: advanced 2152 2153 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2154 @*/ 2155 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2156 { 2157 PetscBool ishdf5; 2158 2159 PetscFunctionBegin; 2160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2161 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2162 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2163 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2164 if (ishdf5) { 2165 #if defined(PETSC_HAVE_HDF5) 2166 PetscViewerFormat format; 2167 PetscCall(PetscViewerGetFormat(viewer, &format)); 2168 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2169 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2170 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2171 #else 2172 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2173 #endif 2174 } 2175 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2176 PetscFunctionReturn(PETSC_SUCCESS); 2177 } 2178 2179 /*@ 2180 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2181 2182 Collective 2183 2184 Input Parameters: 2185 + dm - The `DM` whose labels are to be saved 2186 - viewer - The `PetscViewer` for saving 2187 2188 Level: advanced 2189 2190 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2191 @*/ 2192 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2193 { 2194 PetscBool ishdf5; 2195 2196 PetscFunctionBegin; 2197 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2198 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2199 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2200 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2201 if (ishdf5) { 2202 #if defined(PETSC_HAVE_HDF5) 2203 IS globalPointNumbering; 2204 PetscViewerFormat format; 2205 2206 PetscCall(PetscViewerGetFormat(viewer, &format)); 2207 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2208 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2209 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2210 PetscCall(ISDestroy(&globalPointNumbering)); 2211 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2212 #else 2213 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2214 #endif 2215 } 2216 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2217 PetscFunctionReturn(PETSC_SUCCESS); 2218 } 2219 2220 /*@ 2221 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2222 2223 Collective 2224 2225 Input Parameters: 2226 + dm - The `DM` that contains the topology on which the section to be saved is defined 2227 . viewer - The `PetscViewer` for saving 2228 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2229 2230 Level: advanced 2231 2232 Notes: 2233 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. 2234 2235 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. 2236 2237 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2238 @*/ 2239 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2240 { 2241 PetscBool ishdf5; 2242 2243 PetscFunctionBegin; 2244 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2245 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2246 if (!sectiondm) sectiondm = dm; 2247 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2248 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2249 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2250 if (ishdf5) { 2251 #if defined(PETSC_HAVE_HDF5) 2252 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2253 #else 2254 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2255 #endif 2256 } 2257 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2258 PetscFunctionReturn(PETSC_SUCCESS); 2259 } 2260 2261 /*@ 2262 DMPlexGlobalVectorView - Saves a global vector 2263 2264 Collective 2265 2266 Input Parameters: 2267 + dm - The `DM` that represents the topology 2268 . viewer - The `PetscViewer` to save data with 2269 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2270 - vec - The global vector to be saved 2271 2272 Level: advanced 2273 2274 Notes: 2275 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. 2276 2277 Calling sequence: 2278 .vb 2279 DMCreate(PETSC_COMM_WORLD, &dm); 2280 DMSetType(dm, DMPLEX); 2281 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2282 DMClone(dm, §iondm); 2283 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2284 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2285 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2286 PetscSectionSetChart(section, pStart, pEnd); 2287 PetscSectionSetUp(section); 2288 DMSetLocalSection(sectiondm, section); 2289 PetscSectionDestroy(§ion); 2290 DMGetGlobalVector(sectiondm, &vec); 2291 PetscObjectSetName((PetscObject)vec, "vec_name"); 2292 DMPlexTopologyView(dm, viewer); 2293 DMPlexSectionView(dm, viewer, sectiondm); 2294 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2295 DMRestoreGlobalVector(sectiondm, &vec); 2296 DMDestroy(§iondm); 2297 DMDestroy(&dm); 2298 .ve 2299 2300 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2301 @*/ 2302 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2303 { 2304 PetscBool ishdf5; 2305 2306 PetscFunctionBegin; 2307 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2308 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2309 if (!sectiondm) sectiondm = dm; 2310 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2311 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2312 /* Check consistency */ 2313 { 2314 PetscSection section; 2315 PetscBool includesConstraints; 2316 PetscInt m, m1; 2317 2318 PetscCall(VecGetLocalSize(vec, &m1)); 2319 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2320 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2321 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2322 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2323 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2324 } 2325 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2326 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2327 if (ishdf5) { 2328 #if defined(PETSC_HAVE_HDF5) 2329 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2330 #else 2331 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2332 #endif 2333 } 2334 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2335 PetscFunctionReturn(PETSC_SUCCESS); 2336 } 2337 2338 /*@ 2339 DMPlexLocalVectorView - Saves a local vector 2340 2341 Collective 2342 2343 Input Parameters: 2344 + dm - The `DM` that represents the topology 2345 . viewer - The `PetscViewer` to save data with 2346 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2347 - vec - The local vector to be saved 2348 2349 Level: advanced 2350 2351 Note: 2352 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. 2353 2354 Calling sequence: 2355 .vb 2356 DMCreate(PETSC_COMM_WORLD, &dm); 2357 DMSetType(dm, DMPLEX); 2358 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2359 DMClone(dm, §iondm); 2360 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2361 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2362 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2363 PetscSectionSetChart(section, pStart, pEnd); 2364 PetscSectionSetUp(section); 2365 DMSetLocalSection(sectiondm, section); 2366 DMGetLocalVector(sectiondm, &vec); 2367 PetscObjectSetName((PetscObject)vec, "vec_name"); 2368 DMPlexTopologyView(dm, viewer); 2369 DMPlexSectionView(dm, viewer, sectiondm); 2370 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2371 DMRestoreLocalVector(sectiondm, &vec); 2372 DMDestroy(§iondm); 2373 DMDestroy(&dm); 2374 .ve 2375 2376 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2377 @*/ 2378 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2379 { 2380 PetscBool ishdf5; 2381 2382 PetscFunctionBegin; 2383 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2384 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2385 if (!sectiondm) sectiondm = dm; 2386 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2387 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2388 /* Check consistency */ 2389 { 2390 PetscSection section; 2391 PetscBool includesConstraints; 2392 PetscInt m, m1; 2393 2394 PetscCall(VecGetLocalSize(vec, &m1)); 2395 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2396 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2397 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2398 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2399 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2400 } 2401 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2402 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2403 if (ishdf5) { 2404 #if defined(PETSC_HAVE_HDF5) 2405 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2406 #else 2407 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2408 #endif 2409 } 2410 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2411 PetscFunctionReturn(PETSC_SUCCESS); 2412 } 2413 2414 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2415 { 2416 PetscBool ishdf5; 2417 2418 PetscFunctionBegin; 2419 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2420 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2421 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2422 if (ishdf5) { 2423 #if defined(PETSC_HAVE_HDF5) 2424 PetscViewerFormat format; 2425 PetscCall(PetscViewerGetFormat(viewer, &format)); 2426 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2427 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2428 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2429 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2430 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2431 PetscFunctionReturn(PETSC_SUCCESS); 2432 #else 2433 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2434 #endif 2435 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2436 } 2437 2438 /*@ 2439 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2440 2441 Collective 2442 2443 Input Parameters: 2444 + dm - The `DM` into which the topology is loaded 2445 - viewer - The `PetscViewer` for the saved topology 2446 2447 Output Parameter: 2448 . 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; 2449 `NULL` if unneeded 2450 2451 Level: advanced 2452 2453 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2454 `PetscViewer`, `PetscSF` 2455 @*/ 2456 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2457 { 2458 PetscBool ishdf5; 2459 2460 PetscFunctionBegin; 2461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2462 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2463 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2464 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2465 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2466 if (ishdf5) { 2467 #if defined(PETSC_HAVE_HDF5) 2468 PetscViewerFormat format; 2469 PetscCall(PetscViewerGetFormat(viewer, &format)); 2470 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2471 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2472 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2473 #else 2474 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2475 #endif 2476 } 2477 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2478 PetscFunctionReturn(PETSC_SUCCESS); 2479 } 2480 2481 /*@ 2482 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2483 2484 Collective 2485 2486 Input Parameters: 2487 + dm - The `DM` into which the coordinates are loaded 2488 . viewer - The `PetscViewer` for the saved coordinates 2489 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2490 2491 Level: advanced 2492 2493 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2494 `PetscSF`, `PetscViewer` 2495 @*/ 2496 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2497 { 2498 PetscBool ishdf5; 2499 2500 PetscFunctionBegin; 2501 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2502 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2503 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2504 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2505 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2506 if (ishdf5) { 2507 #if defined(PETSC_HAVE_HDF5) 2508 PetscViewerFormat format; 2509 PetscCall(PetscViewerGetFormat(viewer, &format)); 2510 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2511 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2512 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2513 #else 2514 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2515 #endif 2516 } 2517 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2518 PetscFunctionReturn(PETSC_SUCCESS); 2519 } 2520 2521 /*@ 2522 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2523 2524 Collective 2525 2526 Input Parameters: 2527 + dm - The `DM` into which the labels are loaded 2528 . viewer - The `PetscViewer` for the saved labels 2529 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2530 2531 Level: advanced 2532 2533 Note: 2534 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2535 2536 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2537 `PetscSF`, `PetscViewer` 2538 @*/ 2539 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2540 { 2541 PetscBool ishdf5; 2542 2543 PetscFunctionBegin; 2544 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2545 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2546 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2547 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2548 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2549 if (ishdf5) { 2550 #if defined(PETSC_HAVE_HDF5) 2551 PetscViewerFormat format; 2552 2553 PetscCall(PetscViewerGetFormat(viewer, &format)); 2554 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2555 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2556 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2557 #else 2558 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2559 #endif 2560 } 2561 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2562 PetscFunctionReturn(PETSC_SUCCESS); 2563 } 2564 2565 /*@ 2566 DMPlexSectionLoad - Loads section into a `DMPLEX` 2567 2568 Collective 2569 2570 Input Parameters: 2571 + dm - The `DM` that represents the topology 2572 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2573 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2574 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2575 2576 Output Parameters: 2577 + 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) 2578 - 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) 2579 2580 Level: advanced 2581 2582 Notes: 2583 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. 2584 2585 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. 2586 2587 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. 2588 2589 Example using 2 processes: 2590 .vb 2591 NX (number of points on dm): 4 2592 sectionA : the on-disk section 2593 vecA : a vector associated with sectionA 2594 sectionB : sectiondm's local section constructed in this function 2595 vecB (local) : a vector associated with sectiondm's local section 2596 vecB (global) : a vector associated with sectiondm's global section 2597 2598 rank 0 rank 1 2599 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2600 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2601 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2602 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2603 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2604 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2605 sectionB->atlasDof : 1 0 1 | 1 3 2606 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2607 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2608 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2609 .ve 2610 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2611 2612 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2613 @*/ 2614 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2615 { 2616 PetscBool ishdf5; 2617 2618 PetscFunctionBegin; 2619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2620 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2621 if (!sectiondm) sectiondm = dm; 2622 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2623 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2624 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2625 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2626 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2627 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2628 if (ishdf5) { 2629 #if defined(PETSC_HAVE_HDF5) 2630 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2631 #else 2632 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2633 #endif 2634 } 2635 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2636 PetscFunctionReturn(PETSC_SUCCESS); 2637 } 2638 2639 /*@ 2640 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2641 2642 Collective 2643 2644 Input Parameters: 2645 + dm - The `DM` that represents the topology 2646 . viewer - The `PetscViewer` that represents the on-disk vector data 2647 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2648 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2649 - vec - The global vector to set values of 2650 2651 Level: advanced 2652 2653 Notes: 2654 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. 2655 2656 Calling sequence: 2657 .vb 2658 DMCreate(PETSC_COMM_WORLD, &dm); 2659 DMSetType(dm, DMPLEX); 2660 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2661 DMPlexTopologyLoad(dm, viewer, &sfX); 2662 DMClone(dm, §iondm); 2663 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2664 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2665 DMGetGlobalVector(sectiondm, &vec); 2666 PetscObjectSetName((PetscObject)vec, "vec_name"); 2667 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2668 DMRestoreGlobalVector(sectiondm, &vec); 2669 PetscSFDestroy(&gsf); 2670 PetscSFDestroy(&sfX); 2671 DMDestroy(§iondm); 2672 DMDestroy(&dm); 2673 .ve 2674 2675 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2676 `PetscSF`, `PetscViewer` 2677 @*/ 2678 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2679 { 2680 PetscBool ishdf5; 2681 2682 PetscFunctionBegin; 2683 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2684 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2685 if (!sectiondm) sectiondm = dm; 2686 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2687 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2688 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2689 /* Check consistency */ 2690 { 2691 PetscSection section; 2692 PetscBool includesConstraints; 2693 PetscInt m, m1; 2694 2695 PetscCall(VecGetLocalSize(vec, &m1)); 2696 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2697 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2698 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2699 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2700 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2701 } 2702 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2703 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2704 if (ishdf5) { 2705 #if defined(PETSC_HAVE_HDF5) 2706 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2707 #else 2708 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2709 #endif 2710 } 2711 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2712 PetscFunctionReturn(PETSC_SUCCESS); 2713 } 2714 2715 /*@ 2716 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2717 2718 Collective 2719 2720 Input Parameters: 2721 + dm - The `DM` that represents the topology 2722 . viewer - The `PetscViewer` that represents the on-disk vector data 2723 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2724 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2725 - vec - The local vector to set values of 2726 2727 Level: advanced 2728 2729 Notes: 2730 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. 2731 2732 Calling sequence: 2733 .vb 2734 DMCreate(PETSC_COMM_WORLD, &dm); 2735 DMSetType(dm, DMPLEX); 2736 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2737 DMPlexTopologyLoad(dm, viewer, &sfX); 2738 DMClone(dm, §iondm); 2739 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2740 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2741 DMGetLocalVector(sectiondm, &vec); 2742 PetscObjectSetName((PetscObject)vec, "vec_name"); 2743 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2744 DMRestoreLocalVector(sectiondm, &vec); 2745 PetscSFDestroy(&lsf); 2746 PetscSFDestroy(&sfX); 2747 DMDestroy(§iondm); 2748 DMDestroy(&dm); 2749 .ve 2750 2751 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2752 `PetscSF`, `PetscViewer` 2753 @*/ 2754 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2755 { 2756 PetscBool ishdf5; 2757 2758 PetscFunctionBegin; 2759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2760 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2761 if (!sectiondm) sectiondm = dm; 2762 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2763 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2764 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2765 /* Check consistency */ 2766 { 2767 PetscSection section; 2768 PetscBool includesConstraints; 2769 PetscInt m, m1; 2770 2771 PetscCall(VecGetLocalSize(vec, &m1)); 2772 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2773 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2774 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2775 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2776 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2777 } 2778 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2779 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2780 if (ishdf5) { 2781 #if defined(PETSC_HAVE_HDF5) 2782 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2783 #else 2784 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2785 #endif 2786 } 2787 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2788 PetscFunctionReturn(PETSC_SUCCESS); 2789 } 2790 2791 PetscErrorCode DMDestroy_Plex(DM dm) 2792 { 2793 DM_Plex *mesh = (DM_Plex *)dm->data; 2794 2795 PetscFunctionBegin; 2796 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2797 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2798 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2799 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2800 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2801 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2802 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2803 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2804 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2805 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2806 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2807 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2808 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2809 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2810 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2811 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2812 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2813 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2814 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2815 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2816 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2817 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2818 PetscCall(PetscFree(mesh->cones)); 2819 PetscCall(PetscFree(mesh->coneOrientations)); 2820 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2821 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2822 PetscCall(PetscFree(mesh->supports)); 2823 PetscCall(PetscFree(mesh->cellTypes)); 2824 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2825 PetscCall(PetscFree(mesh->tetgenOpts)); 2826 PetscCall(PetscFree(mesh->triangleOpts)); 2827 PetscCall(PetscFree(mesh->transformType)); 2828 PetscCall(PetscFree(mesh->distributionName)); 2829 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2830 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2831 PetscCall(ISDestroy(&mesh->subpointIS)); 2832 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2833 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2834 if (mesh->periodic.face_sfs) { 2835 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2836 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2837 } 2838 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2839 if (mesh->periodic.periodic_points) { 2840 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2841 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2842 } 2843 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2844 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2845 PetscCall(ISDestroy(&mesh->anchorIS)); 2846 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2847 PetscCall(PetscFree(mesh->parents)); 2848 PetscCall(PetscFree(mesh->childIDs)); 2849 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2850 PetscCall(PetscFree(mesh->children)); 2851 PetscCall(DMDestroy(&mesh->referenceTree)); 2852 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2853 PetscCall(PetscFree(mesh->neighbors)); 2854 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2855 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2856 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2857 PetscCall(PetscFree(mesh)); 2858 PetscFunctionReturn(PETSC_SUCCESS); 2859 } 2860 2861 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2862 { 2863 PetscSection sectionGlobal, sectionLocal; 2864 PetscInt bs = -1, mbs; 2865 PetscInt localSize, localStart = 0; 2866 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2867 MatType mtype; 2868 ISLocalToGlobalMapping ltog; 2869 2870 PetscFunctionBegin; 2871 PetscCall(MatInitializePackage()); 2872 mtype = dm->mattype; 2873 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2874 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2875 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2876 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2877 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2878 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2879 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2880 PetscCall(MatSetType(*J, mtype)); 2881 PetscCall(MatSetFromOptions(*J)); 2882 PetscCall(MatGetBlockSize(*J, &mbs)); 2883 if (mbs > 1) bs = mbs; 2884 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2885 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2886 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2887 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2888 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2889 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2890 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2891 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2892 if (!isShell) { 2893 // There are three states with pblocks, since block starts can have no dofs: 2894 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2895 // TRUE) Block Start: The first entry in a block has been added 2896 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2897 PetscBT blst; 2898 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2899 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2900 const PetscInt *perm = NULL; 2901 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2902 PetscInt pStart, pEnd, dof, cdof, num_fields; 2903 2904 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2905 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2906 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2907 2908 PetscCall(PetscCalloc1(localSize, &pblocks)); 2909 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2910 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2911 // We need to process in the permuted order to get block sizes right 2912 for (PetscInt point = pStart; point < pEnd; ++point) { 2913 const PetscInt p = perm ? perm[point] : point; 2914 2915 switch (dm->blocking_type) { 2916 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2917 PetscInt bdof, offset; 2918 2919 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2920 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2921 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2922 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2923 if (dof > 0) { 2924 // State change 2925 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2926 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2927 2928 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2929 // Signal block concatenation 2930 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2931 } 2932 dof = dof < 0 ? -(dof + 1) : dof; 2933 bdof = cdof && (dof - cdof) ? 1 : dof; 2934 if (dof) { 2935 if (bs < 0) { 2936 bs = bdof; 2937 } else if (bs != bdof) { 2938 bs = 1; 2939 } 2940 } 2941 } break; 2942 case DM_BLOCKING_FIELD_NODE: { 2943 for (PetscInt field = 0; field < num_fields; field++) { 2944 PetscInt num_comp, bdof, offset; 2945 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2946 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2947 if (dof < 0) continue; 2948 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2949 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2950 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); 2951 PetscInt num_nodes = dof / num_comp; 2952 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2953 // Handle possibly constant block size (unlikely) 2954 bdof = cdof && (dof - cdof) ? 1 : dof; 2955 if (dof) { 2956 if (bs < 0) { 2957 bs = bdof; 2958 } else if (bs != bdof) { 2959 bs = 1; 2960 } 2961 } 2962 } 2963 } break; 2964 } 2965 } 2966 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2967 /* Must have same blocksize on all procs (some might have no points) */ 2968 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2969 bsLocal[1] = bs; 2970 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2971 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2972 else bs = bsMinMax[0]; 2973 bs = PetscMax(1, bs); 2974 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2975 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2976 PetscCall(MatSetBlockSize(*J, bs)); 2977 PetscCall(MatSetUp(*J)); 2978 } else { 2979 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2980 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2981 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2982 } 2983 if (pblocks) { // Consolidate blocks 2984 PetscInt nblocks = 0; 2985 pblocks[0] = PetscAbs(pblocks[0]); 2986 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2987 if (pblocks[i] == 0) continue; 2988 // Negative block size indicates the blocks should be concatenated 2989 if (pblocks[i] < 0) { 2990 pblocks[i] = -pblocks[i]; 2991 pblocks[nblocks - 1] += pblocks[i]; 2992 } else { 2993 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2994 } 2995 for (PetscInt j = 1; j < pblocks[i]; j++) 2996 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); 2997 } 2998 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2999 } 3000 PetscCall(PetscFree(pblocks)); 3001 } 3002 PetscCall(MatSetDM(*J, dm)); 3003 PetscFunctionReturn(PETSC_SUCCESS); 3004 } 3005 3006 /*@ 3007 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3008 3009 Not Collective 3010 3011 Input Parameter: 3012 . dm - The `DMPLEX` 3013 3014 Output Parameter: 3015 . subsection - The subdomain section 3016 3017 Level: developer 3018 3019 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3020 @*/ 3021 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3022 { 3023 DM_Plex *mesh = (DM_Plex *)dm->data; 3024 3025 PetscFunctionBegin; 3026 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3027 if (!mesh->subdomainSection) { 3028 PetscSection section; 3029 PetscSF sf; 3030 3031 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3032 PetscCall(DMGetLocalSection(dm, §ion)); 3033 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3034 PetscCall(PetscSFDestroy(&sf)); 3035 } 3036 *subsection = mesh->subdomainSection; 3037 PetscFunctionReturn(PETSC_SUCCESS); 3038 } 3039 3040 /*@ 3041 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3042 3043 Not Collective 3044 3045 Input Parameter: 3046 . dm - The `DMPLEX` 3047 3048 Output Parameters: 3049 + pStart - The first mesh point 3050 - pEnd - The upper bound for mesh points 3051 3052 Level: beginner 3053 3054 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3055 @*/ 3056 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3057 { 3058 DM_Plex *mesh = (DM_Plex *)dm->data; 3059 3060 PetscFunctionBegin; 3061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3062 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3063 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3064 PetscFunctionReturn(PETSC_SUCCESS); 3065 } 3066 3067 /*@ 3068 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3069 3070 Not Collective 3071 3072 Input Parameters: 3073 + dm - The `DMPLEX` 3074 . pStart - The first mesh point 3075 - pEnd - The upper bound for mesh points 3076 3077 Level: beginner 3078 3079 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3080 @*/ 3081 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3082 { 3083 DM_Plex *mesh = (DM_Plex *)dm->data; 3084 3085 PetscFunctionBegin; 3086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3087 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3088 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3089 PetscCall(PetscFree(mesh->cellTypes)); 3090 PetscFunctionReturn(PETSC_SUCCESS); 3091 } 3092 3093 /*@ 3094 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3095 3096 Not Collective 3097 3098 Input Parameters: 3099 + dm - The `DMPLEX` 3100 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3101 3102 Output Parameter: 3103 . size - The cone size for point `p` 3104 3105 Level: beginner 3106 3107 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3108 @*/ 3109 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3110 { 3111 DM_Plex *mesh = (DM_Plex *)dm->data; 3112 3113 PetscFunctionBegin; 3114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3115 PetscAssertPointer(size, 3); 3116 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3117 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3118 PetscFunctionReturn(PETSC_SUCCESS); 3119 } 3120 3121 /*@ 3122 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3123 3124 Not Collective 3125 3126 Input Parameters: 3127 + dm - The `DMPLEX` 3128 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3129 - size - The cone size for point `p` 3130 3131 Level: beginner 3132 3133 Note: 3134 This should be called after `DMPlexSetChart()`. 3135 3136 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3137 @*/ 3138 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3139 { 3140 DM_Plex *mesh = (DM_Plex *)dm->data; 3141 3142 PetscFunctionBegin; 3143 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3144 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3145 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3146 PetscFunctionReturn(PETSC_SUCCESS); 3147 } 3148 3149 /*@C 3150 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3151 3152 Not Collective 3153 3154 Input Parameters: 3155 + dm - The `DMPLEX` 3156 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3157 3158 Output Parameter: 3159 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3160 3161 Level: beginner 3162 3163 Fortran Notes: 3164 `cone` must be declared with 3165 .vb 3166 PetscInt, pointer :: cone(:) 3167 .ve 3168 3169 You must also call `DMPlexRestoreCone()` after you finish using the array. 3170 `DMPlexRestoreCone()` is not needed/available in C. 3171 3172 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3173 @*/ 3174 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3175 { 3176 DM_Plex *mesh = (DM_Plex *)dm->data; 3177 PetscInt off; 3178 3179 PetscFunctionBegin; 3180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3181 PetscAssertPointer(cone, 3); 3182 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3183 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3184 PetscFunctionReturn(PETSC_SUCCESS); 3185 } 3186 3187 /*@ 3188 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3189 3190 Not Collective 3191 3192 Input Parameters: 3193 + dm - The `DMPLEX` 3194 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3195 3196 Output Parameters: 3197 + pConesSection - `PetscSection` describing the layout of `pCones` 3198 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3199 3200 Level: intermediate 3201 3202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3203 @*/ 3204 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3205 { 3206 PetscSection cs, newcs; 3207 PetscInt *cones; 3208 PetscInt *newarr = NULL; 3209 PetscInt n; 3210 3211 PetscFunctionBegin; 3212 PetscCall(DMPlexGetCones(dm, &cones)); 3213 PetscCall(DMPlexGetConeSection(dm, &cs)); 3214 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3215 if (pConesSection) *pConesSection = newcs; 3216 if (pCones) { 3217 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3218 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3219 } 3220 PetscFunctionReturn(PETSC_SUCCESS); 3221 } 3222 3223 /*@ 3224 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3225 3226 Not Collective 3227 3228 Input Parameters: 3229 + dm - The `DMPLEX` 3230 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3231 3232 Output Parameter: 3233 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3234 3235 Level: advanced 3236 3237 Notes: 3238 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3239 3240 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3241 3242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3243 `DMPlexGetDepth()`, `IS` 3244 @*/ 3245 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3246 { 3247 IS *expandedPointsAll; 3248 PetscInt depth; 3249 3250 PetscFunctionBegin; 3251 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3252 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3253 PetscAssertPointer(expandedPoints, 3); 3254 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3255 *expandedPoints = expandedPointsAll[0]; 3256 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3257 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3258 PetscFunctionReturn(PETSC_SUCCESS); 3259 } 3260 3261 /*@ 3262 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3263 (DAG points of depth 0, i.e., without cones). 3264 3265 Not Collective 3266 3267 Input Parameters: 3268 + dm - The `DMPLEX` 3269 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3270 3271 Output Parameters: 3272 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3273 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3274 - sections - (optional) An array of sections which describe mappings from points to their cone points 3275 3276 Level: advanced 3277 3278 Notes: 3279 Like `DMPlexGetConeTuple()` but recursive. 3280 3281 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. 3282 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3283 3284 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\: 3285 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3286 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3287 3288 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3289 `DMPlexGetDepth()`, `PetscSection`, `IS` 3290 @*/ 3291 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3292 { 3293 const PetscInt *arr0 = NULL, *cone = NULL; 3294 PetscInt *arr = NULL, *newarr = NULL; 3295 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3296 IS *expandedPoints_; 3297 PetscSection *sections_; 3298 3299 PetscFunctionBegin; 3300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3301 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3302 if (depth) PetscAssertPointer(depth, 3); 3303 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3304 if (sections) PetscAssertPointer(sections, 5); 3305 PetscCall(ISGetLocalSize(points, &n)); 3306 PetscCall(ISGetIndices(points, &arr0)); 3307 PetscCall(DMPlexGetDepth(dm, &depth_)); 3308 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3309 PetscCall(PetscCalloc1(depth_, §ions_)); 3310 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3311 for (d = depth_ - 1; d >= 0; d--) { 3312 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3313 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3314 for (i = 0; i < n; i++) { 3315 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3316 if (arr[i] >= start && arr[i] < end) { 3317 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3318 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3319 } else { 3320 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3321 } 3322 } 3323 PetscCall(PetscSectionSetUp(sections_[d])); 3324 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3325 PetscCall(PetscMalloc1(newn, &newarr)); 3326 for (i = 0; i < n; i++) { 3327 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3328 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3329 if (cn > 1) { 3330 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3331 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3332 } else { 3333 newarr[co] = arr[i]; 3334 } 3335 } 3336 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3337 arr = newarr; 3338 n = newn; 3339 } 3340 PetscCall(ISRestoreIndices(points, &arr0)); 3341 *depth = depth_; 3342 if (expandedPoints) *expandedPoints = expandedPoints_; 3343 else { 3344 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3345 PetscCall(PetscFree(expandedPoints_)); 3346 } 3347 if (sections) *sections = sections_; 3348 else { 3349 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3350 PetscCall(PetscFree(sections_)); 3351 } 3352 PetscFunctionReturn(PETSC_SUCCESS); 3353 } 3354 3355 /*@ 3356 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3357 3358 Not Collective 3359 3360 Input Parameters: 3361 + dm - The `DMPLEX` 3362 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3363 3364 Output Parameters: 3365 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3366 . expandedPoints - (optional) An array of recursively expanded cones 3367 - sections - (optional) An array of sections which describe mappings from points to their cone points 3368 3369 Level: advanced 3370 3371 Note: 3372 See `DMPlexGetConeRecursive()` 3373 3374 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3375 `DMPlexGetDepth()`, `IS`, `PetscSection` 3376 @*/ 3377 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3378 { 3379 PetscInt d, depth_; 3380 3381 PetscFunctionBegin; 3382 PetscCall(DMPlexGetDepth(dm, &depth_)); 3383 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3384 if (depth) *depth = 0; 3385 if (expandedPoints) { 3386 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3387 PetscCall(PetscFree(*expandedPoints)); 3388 } 3389 if (sections) { 3390 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3391 PetscCall(PetscFree(*sections)); 3392 } 3393 PetscFunctionReturn(PETSC_SUCCESS); 3394 } 3395 3396 /*@ 3397 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 3398 3399 Not Collective 3400 3401 Input Parameters: 3402 + dm - The `DMPLEX` 3403 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3404 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3405 3406 Level: beginner 3407 3408 Note: 3409 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3410 3411 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3412 @*/ 3413 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3414 { 3415 DM_Plex *mesh = (DM_Plex *)dm->data; 3416 PetscInt dof, off, c; 3417 3418 PetscFunctionBegin; 3419 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3420 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3421 if (dof) PetscAssertPointer(cone, 3); 3422 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3423 if (PetscDefined(USE_DEBUG)) { 3424 PetscInt pStart, pEnd; 3425 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3426 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); 3427 for (c = 0; c < dof; ++c) { 3428 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); 3429 mesh->cones[off + c] = cone[c]; 3430 } 3431 } else { 3432 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3433 } 3434 PetscFunctionReturn(PETSC_SUCCESS); 3435 } 3436 3437 /*@C 3438 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3439 3440 Not Collective 3441 3442 Input Parameters: 3443 + dm - The `DMPLEX` 3444 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3445 3446 Output Parameter: 3447 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3448 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3449 3450 Level: beginner 3451 3452 Note: 3453 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3454 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3455 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3456 with the identity. 3457 3458 Fortran Notes: 3459 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3460 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3461 3462 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3463 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3464 @*/ 3465 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3466 { 3467 DM_Plex *mesh = (DM_Plex *)dm->data; 3468 PetscInt off; 3469 3470 PetscFunctionBegin; 3471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3472 if (PetscDefined(USE_DEBUG)) { 3473 PetscInt dof; 3474 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3475 if (dof) PetscAssertPointer(coneOrientation, 3); 3476 } 3477 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3478 3479 *coneOrientation = &mesh->coneOrientations[off]; 3480 PetscFunctionReturn(PETSC_SUCCESS); 3481 } 3482 3483 /*@ 3484 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3485 3486 Not Collective 3487 3488 Input Parameters: 3489 + dm - The `DMPLEX` 3490 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3491 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3492 3493 Level: beginner 3494 3495 Notes: 3496 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3497 3498 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3499 3500 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3501 @*/ 3502 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3503 { 3504 DM_Plex *mesh = (DM_Plex *)dm->data; 3505 PetscInt pStart, pEnd; 3506 PetscInt dof, off, c; 3507 3508 PetscFunctionBegin; 3509 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3510 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3511 if (dof) PetscAssertPointer(coneOrientation, 3); 3512 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3513 if (PetscDefined(USE_DEBUG)) { 3514 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3515 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); 3516 for (c = 0; c < dof; ++c) { 3517 PetscInt cdof, o = coneOrientation[c]; 3518 3519 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3520 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); 3521 mesh->coneOrientations[off + c] = o; 3522 } 3523 } else { 3524 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3525 } 3526 PetscFunctionReturn(PETSC_SUCCESS); 3527 } 3528 3529 /*@ 3530 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3531 3532 Not Collective 3533 3534 Input Parameters: 3535 + dm - The `DMPLEX` 3536 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3537 . conePos - The local index in the cone where the point should be put 3538 - conePoint - The mesh point to insert 3539 3540 Level: beginner 3541 3542 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3543 @*/ 3544 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3545 { 3546 DM_Plex *mesh = (DM_Plex *)dm->data; 3547 PetscInt pStart, pEnd; 3548 PetscInt dof, off; 3549 3550 PetscFunctionBegin; 3551 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3552 if (PetscDefined(USE_DEBUG)) { 3553 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3554 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); 3555 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); 3556 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3557 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); 3558 } 3559 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3560 mesh->cones[off + conePos] = conePoint; 3561 PetscFunctionReturn(PETSC_SUCCESS); 3562 } 3563 3564 /*@ 3565 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3566 3567 Not Collective 3568 3569 Input Parameters: 3570 + dm - The `DMPLEX` 3571 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3572 . conePos - The local index in the cone where the point should be put 3573 - coneOrientation - The point orientation to insert 3574 3575 Level: beginner 3576 3577 Note: 3578 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3579 3580 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3581 @*/ 3582 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3583 { 3584 DM_Plex *mesh = (DM_Plex *)dm->data; 3585 PetscInt pStart, pEnd; 3586 PetscInt dof, off; 3587 3588 PetscFunctionBegin; 3589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3590 if (PetscDefined(USE_DEBUG)) { 3591 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3592 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); 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->coneOrientations[off + conePos] = coneOrientation; 3598 PetscFunctionReturn(PETSC_SUCCESS); 3599 } 3600 3601 /*@C 3602 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point 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 3610 Output Parameters: 3611 + cone - An array of points which are on the in-edges for point `p` 3612 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3613 integer giving the prescription for cone traversal. 3614 3615 Level: beginner 3616 3617 Notes: 3618 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3619 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3620 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3621 with the identity. 3622 3623 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3624 3625 Fortran Notes: 3626 `cone` and `ornt` must be declared with 3627 .vb 3628 PetscInt, pointer :: cone(:) 3629 PetscInt, pointer :: ornt(:) 3630 .ve 3631 3632 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3633 @*/ 3634 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3635 { 3636 DM_Plex *mesh = (DM_Plex *)dm->data; 3637 3638 PetscFunctionBegin; 3639 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3640 if (mesh->tr) { 3641 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3642 } else { 3643 PetscInt off; 3644 if (PetscDefined(USE_DEBUG)) { 3645 PetscInt dof; 3646 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3647 if (dof) { 3648 if (cone) PetscAssertPointer(cone, 3); 3649 if (ornt) PetscAssertPointer(ornt, 4); 3650 } 3651 } 3652 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3653 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3654 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3655 } 3656 PetscFunctionReturn(PETSC_SUCCESS); 3657 } 3658 3659 /*@C 3660 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3661 3662 Not Collective 3663 3664 Input Parameters: 3665 + dm - The DMPlex 3666 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3667 . cone - An array of points which are on the in-edges for point p 3668 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3669 integer giving the prescription for cone traversal. 3670 3671 Level: beginner 3672 3673 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3674 @*/ 3675 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3676 { 3677 DM_Plex *mesh = (DM_Plex *)dm->data; 3678 3679 PetscFunctionBegin; 3680 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3681 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3682 PetscFunctionReturn(PETSC_SUCCESS); 3683 } 3684 3685 /*@ 3686 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3687 3688 Not Collective 3689 3690 Input Parameters: 3691 + dm - The `DMPLEX` 3692 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3693 3694 Output Parameter: 3695 . size - The support size for point `p` 3696 3697 Level: beginner 3698 3699 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3700 @*/ 3701 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3702 { 3703 DM_Plex *mesh = (DM_Plex *)dm->data; 3704 3705 PetscFunctionBegin; 3706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3707 PetscAssertPointer(size, 3); 3708 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3709 PetscFunctionReturn(PETSC_SUCCESS); 3710 } 3711 3712 /*@ 3713 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3714 3715 Not Collective 3716 3717 Input Parameters: 3718 + dm - The `DMPLEX` 3719 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3720 - size - The support size for point `p` 3721 3722 Level: beginner 3723 3724 Note: 3725 This should be called after `DMPlexSetChart()`. 3726 3727 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3728 @*/ 3729 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3730 { 3731 DM_Plex *mesh = (DM_Plex *)dm->data; 3732 3733 PetscFunctionBegin; 3734 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3735 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3736 PetscFunctionReturn(PETSC_SUCCESS); 3737 } 3738 3739 /*@C 3740 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3741 3742 Not Collective 3743 3744 Input Parameters: 3745 + dm - The `DMPLEX` 3746 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3747 3748 Output Parameter: 3749 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3750 3751 Level: beginner 3752 3753 Fortran Notes: 3754 `support` must be declared with 3755 .vb 3756 PetscInt, pointer :: support(:) 3757 .ve 3758 3759 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3760 `DMPlexRestoreSupport()` is not needed/available in C. 3761 3762 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3763 @*/ 3764 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3765 { 3766 DM_Plex *mesh = (DM_Plex *)dm->data; 3767 PetscInt off; 3768 3769 PetscFunctionBegin; 3770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3771 PetscAssertPointer(support, 3); 3772 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3773 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3774 PetscFunctionReturn(PETSC_SUCCESS); 3775 } 3776 3777 /*@ 3778 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3779 3780 Not Collective 3781 3782 Input Parameters: 3783 + dm - The `DMPLEX` 3784 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3785 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3786 3787 Level: beginner 3788 3789 Note: 3790 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3791 3792 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3793 @*/ 3794 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3795 { 3796 DM_Plex *mesh = (DM_Plex *)dm->data; 3797 PetscInt pStart, pEnd; 3798 PetscInt dof, off, c; 3799 3800 PetscFunctionBegin; 3801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3802 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3803 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3804 if (dof) PetscAssertPointer(support, 3); 3805 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3806 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); 3807 for (c = 0; c < dof; ++c) { 3808 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); 3809 mesh->supports[off + c] = support[c]; 3810 } 3811 PetscFunctionReturn(PETSC_SUCCESS); 3812 } 3813 3814 /*@ 3815 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 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 . supportPos - The local index in the cone where the point should be put 3823 - supportPoint - The mesh point to insert 3824 3825 Level: beginner 3826 3827 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3828 @*/ 3829 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3830 { 3831 DM_Plex *mesh = (DM_Plex *)dm->data; 3832 PetscInt pStart, pEnd; 3833 PetscInt dof, off; 3834 3835 PetscFunctionBegin; 3836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3837 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3838 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3839 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3840 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); 3841 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); 3842 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); 3843 mesh->supports[off + supportPos] = supportPoint; 3844 PetscFunctionReturn(PETSC_SUCCESS); 3845 } 3846 3847 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3848 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3849 { 3850 switch (ct) { 3851 case DM_POLYTOPE_SEGMENT: 3852 if (o == -1) return -2; 3853 break; 3854 case DM_POLYTOPE_TRIANGLE: 3855 if (o == -3) return -1; 3856 if (o == -2) return -3; 3857 if (o == -1) return -2; 3858 break; 3859 case DM_POLYTOPE_QUADRILATERAL: 3860 if (o == -4) return -2; 3861 if (o == -3) return -1; 3862 if (o == -2) return -4; 3863 if (o == -1) return -3; 3864 break; 3865 default: 3866 return o; 3867 } 3868 return o; 3869 } 3870 3871 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3872 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3873 { 3874 switch (ct) { 3875 case DM_POLYTOPE_SEGMENT: 3876 if ((o == -2) || (o == 1)) return -1; 3877 if (o == -1) return 0; 3878 break; 3879 case DM_POLYTOPE_TRIANGLE: 3880 if (o == -3) return -2; 3881 if (o == -2) return -1; 3882 if (o == -1) return -3; 3883 break; 3884 case DM_POLYTOPE_QUADRILATERAL: 3885 if (o == -4) return -2; 3886 if (o == -3) return -1; 3887 if (o == -2) return -4; 3888 if (o == -1) return -3; 3889 break; 3890 default: 3891 return o; 3892 } 3893 return o; 3894 } 3895 3896 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3897 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3898 { 3899 PetscInt pStart, pEnd, p; 3900 3901 PetscFunctionBegin; 3902 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3903 for (p = pStart; p < pEnd; ++p) { 3904 const PetscInt *cone, *ornt; 3905 PetscInt coneSize, c; 3906 3907 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3908 PetscCall(DMPlexGetCone(dm, p, &cone)); 3909 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3910 for (c = 0; c < coneSize; ++c) { 3911 DMPolytopeType ct; 3912 const PetscInt o = ornt[c]; 3913 3914 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3915 switch (ct) { 3916 case DM_POLYTOPE_SEGMENT: 3917 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3918 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3919 break; 3920 case DM_POLYTOPE_TRIANGLE: 3921 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3922 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3923 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3924 break; 3925 case DM_POLYTOPE_QUADRILATERAL: 3926 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3927 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3928 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3929 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3930 break; 3931 default: 3932 break; 3933 } 3934 } 3935 } 3936 PetscFunctionReturn(PETSC_SUCCESS); 3937 } 3938 3939 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3940 { 3941 DM_Plex *mesh = (DM_Plex *)dm->data; 3942 3943 PetscFunctionBeginHot; 3944 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3945 if (useCone) { 3946 PetscCall(DMPlexGetConeSize(dm, p, size)); 3947 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3948 } else { 3949 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3950 PetscCall(DMPlexGetSupport(dm, p, arr)); 3951 } 3952 } else { 3953 if (useCone) { 3954 const PetscSection s = mesh->coneSection; 3955 const PetscInt ps = p - s->pStart; 3956 const PetscInt off = s->atlasOff[ps]; 3957 3958 *size = s->atlasDof[ps]; 3959 *arr = mesh->cones + off; 3960 *ornt = mesh->coneOrientations + off; 3961 } else { 3962 const PetscSection s = mesh->supportSection; 3963 const PetscInt ps = p - s->pStart; 3964 const PetscInt off = s->atlasOff[ps]; 3965 3966 *size = s->atlasDof[ps]; 3967 *arr = mesh->supports + off; 3968 } 3969 } 3970 PetscFunctionReturn(PETSC_SUCCESS); 3971 } 3972 3973 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3974 { 3975 DM_Plex *mesh = (DM_Plex *)dm->data; 3976 3977 PetscFunctionBeginHot; 3978 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3979 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3980 } 3981 PetscFunctionReturn(PETSC_SUCCESS); 3982 } 3983 3984 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3985 { 3986 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3987 PetscInt *closure; 3988 const PetscInt *tmp = NULL, *tmpO = NULL; 3989 PetscInt off = 0, tmpSize, t; 3990 3991 PetscFunctionBeginHot; 3992 if (ornt) { 3993 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3994 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; 3995 } 3996 if (*points) { 3997 closure = *points; 3998 } else { 3999 PetscInt maxConeSize, maxSupportSize; 4000 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4001 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4002 } 4003 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4004 if (ct == DM_POLYTOPE_UNKNOWN) { 4005 closure[off++] = p; 4006 closure[off++] = 0; 4007 for (t = 0; t < tmpSize; ++t) { 4008 closure[off++] = tmp[t]; 4009 closure[off++] = tmpO ? tmpO[t] : 0; 4010 } 4011 } else { 4012 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4013 4014 /* We assume that cells with a valid type have faces with a valid type */ 4015 closure[off++] = p; 4016 closure[off++] = ornt; 4017 for (t = 0; t < tmpSize; ++t) { 4018 DMPolytopeType ft; 4019 4020 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4021 closure[off++] = tmp[arr[t]]; 4022 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4023 } 4024 } 4025 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4026 if (numPoints) *numPoints = tmpSize + 1; 4027 if (points) *points = closure; 4028 PetscFunctionReturn(PETSC_SUCCESS); 4029 } 4030 4031 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4032 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4033 { 4034 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4035 const PetscInt *cone, *ornt; 4036 PetscInt *pts, *closure = NULL; 4037 DMPolytopeType ft; 4038 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4039 PetscInt dim, coneSize, c, d, clSize, cl; 4040 4041 PetscFunctionBeginHot; 4042 PetscCall(DMGetDimension(dm, &dim)); 4043 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4044 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4045 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4046 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4047 maxSize = PetscMax(coneSeries, supportSeries); 4048 if (*points) { 4049 pts = *points; 4050 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4051 c = 0; 4052 pts[c++] = point; 4053 pts[c++] = o; 4054 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4055 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4056 for (cl = 0; cl < clSize * 2; cl += 2) { 4057 pts[c++] = closure[cl]; 4058 pts[c++] = closure[cl + 1]; 4059 } 4060 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4061 for (cl = 0; cl < clSize * 2; cl += 2) { 4062 pts[c++] = closure[cl]; 4063 pts[c++] = closure[cl + 1]; 4064 } 4065 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4066 for (d = 2; d < coneSize; ++d) { 4067 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4068 pts[c++] = cone[arr[d * 2 + 0]]; 4069 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4070 } 4071 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4072 if (dim >= 3) { 4073 for (d = 2; d < coneSize; ++d) { 4074 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4075 const PetscInt *fcone, *fornt; 4076 PetscInt fconeSize, fc, i; 4077 4078 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4079 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4080 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4081 for (fc = 0; fc < fconeSize; ++fc) { 4082 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4083 const PetscInt co = farr[fc * 2 + 1]; 4084 4085 for (i = 0; i < c; i += 2) 4086 if (pts[i] == cp) break; 4087 if (i == c) { 4088 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4089 pts[c++] = cp; 4090 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4091 } 4092 } 4093 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4094 } 4095 } 4096 *numPoints = c / 2; 4097 *points = pts; 4098 PetscFunctionReturn(PETSC_SUCCESS); 4099 } 4100 4101 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4102 { 4103 DMPolytopeType ct; 4104 PetscInt *closure, *fifo; 4105 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4106 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4107 PetscInt depth, maxSize; 4108 4109 PetscFunctionBeginHot; 4110 PetscCall(DMPlexGetDepth(dm, &depth)); 4111 if (depth == 1) { 4112 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4113 PetscFunctionReturn(PETSC_SUCCESS); 4114 } 4115 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4116 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; 4117 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4118 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4119 PetscFunctionReturn(PETSC_SUCCESS); 4120 } 4121 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4122 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4123 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4124 maxSize = PetscMax(coneSeries, supportSeries); 4125 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4126 if (*points) { 4127 closure = *points; 4128 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4129 closure[closureSize++] = p; 4130 closure[closureSize++] = ornt; 4131 fifo[fifoSize++] = p; 4132 fifo[fifoSize++] = ornt; 4133 fifo[fifoSize++] = ct; 4134 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4135 while (fifoSize - fifoStart) { 4136 const PetscInt q = fifo[fifoStart++]; 4137 const PetscInt o = fifo[fifoStart++]; 4138 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4139 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4140 const PetscInt *tmp, *tmpO = NULL; 4141 PetscInt tmpSize, t; 4142 4143 if (PetscDefined(USE_DEBUG)) { 4144 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4145 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); 4146 } 4147 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4148 for (t = 0; t < tmpSize; ++t) { 4149 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4150 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4151 const PetscInt cp = tmp[ip]; 4152 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4153 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4154 PetscInt c; 4155 4156 /* Check for duplicate */ 4157 for (c = 0; c < closureSize; c += 2) { 4158 if (closure[c] == cp) break; 4159 } 4160 if (c == closureSize) { 4161 closure[closureSize++] = cp; 4162 closure[closureSize++] = co; 4163 fifo[fifoSize++] = cp; 4164 fifo[fifoSize++] = co; 4165 fifo[fifoSize++] = ct; 4166 } 4167 } 4168 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4169 } 4170 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4171 if (numPoints) *numPoints = closureSize / 2; 4172 if (points) *points = closure; 4173 PetscFunctionReturn(PETSC_SUCCESS); 4174 } 4175 4176 /*@C 4177 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4178 4179 Not Collective 4180 4181 Input Parameters: 4182 + dm - The `DMPLEX` 4183 . p - The mesh point 4184 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4185 4186 Input/Output Parameter: 4187 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4188 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4189 otherwise the provided array is used to hold the values 4190 4191 Output Parameter: 4192 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4193 4194 Level: beginner 4195 4196 Note: 4197 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4198 4199 Fortran Notes: 4200 `points` must be declared with 4201 .vb 4202 PetscInt, pointer :: points(:) 4203 .ve 4204 and is always allocated by the function. 4205 4206 The `numPoints` argument is not present in the Fortran binding. 4207 4208 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4209 @*/ 4210 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4211 { 4212 PetscFunctionBeginHot; 4213 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4214 if (numPoints) PetscAssertPointer(numPoints, 4); 4215 if (points) PetscAssertPointer(points, 5); 4216 if (PetscDefined(USE_DEBUG)) { 4217 PetscInt pStart, pEnd; 4218 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4219 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); 4220 } 4221 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4222 PetscFunctionReturn(PETSC_SUCCESS); 4223 } 4224 4225 /*@C 4226 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4227 4228 Not Collective 4229 4230 Input Parameters: 4231 + dm - The `DMPLEX` 4232 . p - The mesh point 4233 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4234 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4235 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4236 4237 Level: beginner 4238 4239 Note: 4240 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4241 4242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4243 @*/ 4244 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4245 { 4246 PetscFunctionBeginHot; 4247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4248 if (numPoints) *numPoints = 0; 4249 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4250 PetscFunctionReturn(PETSC_SUCCESS); 4251 } 4252 4253 /*@ 4254 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4255 4256 Not Collective 4257 4258 Input Parameter: 4259 . dm - The `DMPLEX` 4260 4261 Output Parameters: 4262 + maxConeSize - The maximum number of in-edges 4263 - maxSupportSize - The maximum number of out-edges 4264 4265 Level: beginner 4266 4267 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4268 @*/ 4269 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4270 { 4271 DM_Plex *mesh = (DM_Plex *)dm->data; 4272 4273 PetscFunctionBegin; 4274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4275 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4276 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4277 PetscFunctionReturn(PETSC_SUCCESS); 4278 } 4279 4280 PetscErrorCode DMSetUp_Plex(DM dm) 4281 { 4282 DM_Plex *mesh = (DM_Plex *)dm->data; 4283 PetscInt size, maxSupportSize; 4284 4285 PetscFunctionBegin; 4286 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4287 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4288 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4289 PetscCall(PetscMalloc1(size, &mesh->cones)); 4290 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4291 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4292 if (maxSupportSize) { 4293 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4294 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4295 PetscCall(PetscMalloc1(size, &mesh->supports)); 4296 } 4297 PetscFunctionReturn(PETSC_SUCCESS); 4298 } 4299 4300 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4301 { 4302 PetscFunctionBegin; 4303 if (subdm) PetscCall(DMClone(dm, subdm)); 4304 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4305 if (subdm) (*subdm)->useNatural = dm->useNatural; 4306 if (dm->useNatural && dm->sfMigration) { 4307 PetscSF sfNatural; 4308 4309 (*subdm)->sfMigration = dm->sfMigration; 4310 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4311 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4312 (*subdm)->sfNatural = sfNatural; 4313 } 4314 PetscFunctionReturn(PETSC_SUCCESS); 4315 } 4316 4317 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4318 { 4319 PetscInt i = 0; 4320 4321 PetscFunctionBegin; 4322 PetscCall(DMClone(dms[0], superdm)); 4323 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4324 (*superdm)->useNatural = PETSC_FALSE; 4325 for (i = 0; i < len; i++) { 4326 if (dms[i]->useNatural && dms[i]->sfMigration) { 4327 PetscSF sfNatural; 4328 4329 (*superdm)->sfMigration = dms[i]->sfMigration; 4330 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4331 (*superdm)->useNatural = PETSC_TRUE; 4332 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4333 (*superdm)->sfNatural = sfNatural; 4334 break; 4335 } 4336 } 4337 PetscFunctionReturn(PETSC_SUCCESS); 4338 } 4339 4340 /*@ 4341 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4342 4343 Not Collective 4344 4345 Input Parameter: 4346 . dm - The `DMPLEX` 4347 4348 Level: beginner 4349 4350 Note: 4351 This should be called after all calls to `DMPlexSetCone()` 4352 4353 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4354 @*/ 4355 PetscErrorCode DMPlexSymmetrize(DM dm) 4356 { 4357 DM_Plex *mesh = (DM_Plex *)dm->data; 4358 PetscInt *offsets; 4359 PetscInt supportSize; 4360 PetscInt pStart, pEnd, p; 4361 4362 PetscFunctionBegin; 4363 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4364 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4365 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4366 /* Calculate support sizes */ 4367 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4368 for (p = pStart; p < pEnd; ++p) { 4369 PetscInt dof, off, c; 4370 4371 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4372 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4373 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4374 } 4375 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4376 /* Calculate supports */ 4377 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4378 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4379 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4380 for (p = pStart; p < pEnd; ++p) { 4381 PetscInt dof, off, c; 4382 4383 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4384 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4385 for (c = off; c < off + dof; ++c) { 4386 const PetscInt q = mesh->cones[c]; 4387 PetscInt offS; 4388 4389 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4390 4391 mesh->supports[offS + offsets[q]] = p; 4392 ++offsets[q]; 4393 } 4394 } 4395 PetscCall(PetscFree(offsets)); 4396 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4397 PetscFunctionReturn(PETSC_SUCCESS); 4398 } 4399 4400 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4401 { 4402 IS stratumIS; 4403 4404 PetscFunctionBegin; 4405 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4406 if (PetscDefined(USE_DEBUG)) { 4407 PetscInt qStart, qEnd, numLevels, level; 4408 PetscBool overlap = PETSC_FALSE; 4409 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4410 for (level = 0; level < numLevels; level++) { 4411 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4412 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4413 overlap = PETSC_TRUE; 4414 break; 4415 } 4416 } 4417 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); 4418 } 4419 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4420 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4421 PetscCall(ISDestroy(&stratumIS)); 4422 PetscFunctionReturn(PETSC_SUCCESS); 4423 } 4424 4425 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4426 { 4427 PetscInt *pMin, *pMax; 4428 PetscInt pStart, pEnd; 4429 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4430 4431 PetscFunctionBegin; 4432 { 4433 DMLabel label2; 4434 4435 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4436 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4437 } 4438 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4439 for (PetscInt p = pStart; p < pEnd; ++p) { 4440 DMPolytopeType ct; 4441 4442 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4443 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4444 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4445 } 4446 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4447 for (PetscInt d = dmin; d <= dmax; ++d) { 4448 pMin[d] = PETSC_INT_MAX; 4449 pMax[d] = PETSC_INT_MIN; 4450 } 4451 for (PetscInt p = pStart; p < pEnd; ++p) { 4452 DMPolytopeType ct; 4453 PetscInt d; 4454 4455 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4456 d = DMPolytopeTypeGetDim(ct); 4457 pMin[d] = PetscMin(p, pMin[d]); 4458 pMax[d] = PetscMax(p, pMax[d]); 4459 } 4460 for (PetscInt d = dmin; d <= dmax; ++d) { 4461 if (pMin[d] > pMax[d]) continue; 4462 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4463 } 4464 PetscCall(PetscFree2(pMin, pMax)); 4465 PetscFunctionReturn(PETSC_SUCCESS); 4466 } 4467 4468 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4469 { 4470 PetscInt pStart, pEnd; 4471 PetscInt numRoots = 0, numLeaves = 0; 4472 4473 PetscFunctionBegin; 4474 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4475 { 4476 /* Initialize roots and count leaves */ 4477 PetscInt sMin = PETSC_INT_MAX; 4478 PetscInt sMax = PETSC_INT_MIN; 4479 PetscInt coneSize, supportSize; 4480 4481 for (PetscInt p = pStart; p < pEnd; ++p) { 4482 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4483 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4484 if (!coneSize && supportSize) { 4485 sMin = PetscMin(p, sMin); 4486 sMax = PetscMax(p, sMax); 4487 ++numRoots; 4488 } else if (!supportSize && coneSize) { 4489 ++numLeaves; 4490 } else if (!supportSize && !coneSize) { 4491 /* Isolated points */ 4492 sMin = PetscMin(p, sMin); 4493 sMax = PetscMax(p, sMax); 4494 } 4495 } 4496 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4497 } 4498 4499 if (numRoots + numLeaves == (pEnd - pStart)) { 4500 PetscInt sMin = PETSC_INT_MAX; 4501 PetscInt sMax = PETSC_INT_MIN; 4502 PetscInt coneSize, supportSize; 4503 4504 for (PetscInt p = pStart; p < pEnd; ++p) { 4505 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4506 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4507 if (!supportSize && coneSize) { 4508 sMin = PetscMin(p, sMin); 4509 sMax = PetscMax(p, sMax); 4510 } 4511 } 4512 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4513 } else { 4514 PetscInt level = 0; 4515 PetscInt qStart, qEnd; 4516 4517 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4518 while (qEnd > qStart) { 4519 PetscInt sMin = PETSC_INT_MAX; 4520 PetscInt sMax = PETSC_INT_MIN; 4521 4522 for (PetscInt q = qStart; q < qEnd; ++q) { 4523 const PetscInt *support; 4524 PetscInt supportSize; 4525 4526 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4527 PetscCall(DMPlexGetSupport(dm, q, &support)); 4528 for (PetscInt s = 0; s < supportSize; ++s) { 4529 sMin = PetscMin(support[s], sMin); 4530 sMax = PetscMax(support[s], sMax); 4531 } 4532 } 4533 PetscCall(DMLabelGetNumValues(label, &level)); 4534 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4535 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4536 } 4537 } 4538 PetscFunctionReturn(PETSC_SUCCESS); 4539 } 4540 4541 /*@ 4542 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4543 4544 Collective 4545 4546 Input Parameter: 4547 . dm - The `DMPLEX` 4548 4549 Level: beginner 4550 4551 Notes: 4552 The strata group all points of the same grade, and this function calculates the strata. This 4553 grade can be seen as the height (or depth) of the point in the DAG. 4554 4555 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4556 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4557 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4558 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4559 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4560 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4561 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4562 4563 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4564 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4565 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 4566 to interpolate only that one (e0), so that 4567 .vb 4568 cone(c0) = {e0, v2} 4569 cone(e0) = {v0, v1} 4570 .ve 4571 If `DMPlexStratify()` is run on this mesh, it will give depths 4572 .vb 4573 depth 0 = {v0, v1, v2} 4574 depth 1 = {e0, c0} 4575 .ve 4576 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4577 4578 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4579 4580 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4581 @*/ 4582 PetscErrorCode DMPlexStratify(DM dm) 4583 { 4584 DM_Plex *mesh = (DM_Plex *)dm->data; 4585 DMLabel label; 4586 PetscBool flg = PETSC_FALSE; 4587 4588 PetscFunctionBegin; 4589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4590 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4591 4592 // Create depth label 4593 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4594 PetscCall(DMCreateLabel(dm, "depth")); 4595 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4596 4597 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4598 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4599 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4600 4601 { /* just in case there is an empty process */ 4602 PetscInt numValues, maxValues = 0, v; 4603 4604 PetscCall(DMLabelGetNumValues(label, &numValues)); 4605 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4606 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4607 } 4608 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4609 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4610 PetscFunctionReturn(PETSC_SUCCESS); 4611 } 4612 4613 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4614 { 4615 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4616 PetscInt dim, depth, pheight, coneSize; 4617 4618 PetscFunctionBeginHot; 4619 PetscCall(DMGetDimension(dm, &dim)); 4620 PetscCall(DMPlexGetDepth(dm, &depth)); 4621 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4622 pheight = depth - pdepth; 4623 if (depth <= 1) { 4624 switch (pdepth) { 4625 case 0: 4626 ct = DM_POLYTOPE_POINT; 4627 break; 4628 case 1: 4629 switch (coneSize) { 4630 case 2: 4631 ct = DM_POLYTOPE_SEGMENT; 4632 break; 4633 case 3: 4634 ct = DM_POLYTOPE_TRIANGLE; 4635 break; 4636 case 4: 4637 switch (dim) { 4638 case 2: 4639 ct = DM_POLYTOPE_QUADRILATERAL; 4640 break; 4641 case 3: 4642 ct = DM_POLYTOPE_TETRAHEDRON; 4643 break; 4644 default: 4645 break; 4646 } 4647 break; 4648 case 5: 4649 ct = DM_POLYTOPE_PYRAMID; 4650 break; 4651 case 6: 4652 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4653 break; 4654 case 8: 4655 ct = DM_POLYTOPE_HEXAHEDRON; 4656 break; 4657 default: 4658 break; 4659 } 4660 } 4661 } else { 4662 if (pdepth == 0) { 4663 ct = DM_POLYTOPE_POINT; 4664 } else if (pheight == 0) { 4665 switch (dim) { 4666 case 1: 4667 switch (coneSize) { 4668 case 2: 4669 ct = DM_POLYTOPE_SEGMENT; 4670 break; 4671 default: 4672 break; 4673 } 4674 break; 4675 case 2: 4676 switch (coneSize) { 4677 case 3: 4678 ct = DM_POLYTOPE_TRIANGLE; 4679 break; 4680 case 4: 4681 ct = DM_POLYTOPE_QUADRILATERAL; 4682 break; 4683 default: 4684 break; 4685 } 4686 break; 4687 case 3: 4688 switch (coneSize) { 4689 case 4: 4690 ct = DM_POLYTOPE_TETRAHEDRON; 4691 break; 4692 case 5: { 4693 const PetscInt *cone; 4694 PetscInt faceConeSize; 4695 4696 PetscCall(DMPlexGetCone(dm, p, &cone)); 4697 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4698 switch (faceConeSize) { 4699 case 3: 4700 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4701 break; 4702 case 4: 4703 ct = DM_POLYTOPE_PYRAMID; 4704 break; 4705 } 4706 } break; 4707 case 6: 4708 ct = DM_POLYTOPE_HEXAHEDRON; 4709 break; 4710 default: 4711 break; 4712 } 4713 break; 4714 default: 4715 break; 4716 } 4717 } else if (pheight > 0) { 4718 switch (coneSize) { 4719 case 2: 4720 ct = DM_POLYTOPE_SEGMENT; 4721 break; 4722 case 3: 4723 ct = DM_POLYTOPE_TRIANGLE; 4724 break; 4725 case 4: 4726 ct = DM_POLYTOPE_QUADRILATERAL; 4727 break; 4728 default: 4729 break; 4730 } 4731 } 4732 } 4733 *pt = ct; 4734 PetscFunctionReturn(PETSC_SUCCESS); 4735 } 4736 4737 /*@ 4738 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4739 4740 Collective 4741 4742 Input Parameter: 4743 . dm - The `DMPLEX` 4744 4745 Level: developer 4746 4747 Note: 4748 This function is normally called automatically when a cell type is requested. It creates an 4749 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4750 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4751 4752 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4753 4754 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4755 @*/ 4756 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4757 { 4758 DM_Plex *mesh; 4759 DMLabel ctLabel; 4760 PetscInt pStart, pEnd, p; 4761 4762 PetscFunctionBegin; 4763 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4764 mesh = (DM_Plex *)dm->data; 4765 PetscCall(DMCreateLabel(dm, "celltype")); 4766 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4767 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4768 PetscCall(PetscFree(mesh->cellTypes)); 4769 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4770 for (p = pStart; p < pEnd; ++p) { 4771 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4772 PetscInt pdepth; 4773 4774 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4775 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4776 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]); 4777 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4778 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4779 } 4780 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4781 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4782 PetscFunctionReturn(PETSC_SUCCESS); 4783 } 4784 4785 /*@C 4786 DMPlexGetJoin - Get an array for the join of the set of points 4787 4788 Not Collective 4789 4790 Input Parameters: 4791 + dm - The `DMPLEX` object 4792 . numPoints - The number of input points for the join 4793 - points - The input points 4794 4795 Output Parameters: 4796 + numCoveredPoints - The number of points in the join 4797 - coveredPoints - The points in the join 4798 4799 Level: intermediate 4800 4801 Note: 4802 Currently, this is restricted to a single level join 4803 4804 Fortran Notes: 4805 `converedPoints` must be declared with 4806 .vb 4807 PetscInt, pointer :: coveredPints(:) 4808 .ve 4809 4810 The `numCoveredPoints` argument is not present in the Fortran binding. 4811 4812 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4813 @*/ 4814 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4815 { 4816 DM_Plex *mesh = (DM_Plex *)dm->data; 4817 PetscInt *join[2]; 4818 PetscInt joinSize, i = 0; 4819 PetscInt dof, off, p, c, m; 4820 PetscInt maxSupportSize; 4821 4822 PetscFunctionBegin; 4823 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4824 PetscAssertPointer(points, 3); 4825 PetscAssertPointer(numCoveredPoints, 4); 4826 PetscAssertPointer(coveredPoints, 5); 4827 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4828 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4829 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4830 /* Copy in support of first point */ 4831 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4832 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4833 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4834 /* Check each successive support */ 4835 for (p = 1; p < numPoints; ++p) { 4836 PetscInt newJoinSize = 0; 4837 4838 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4839 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4840 for (c = 0; c < dof; ++c) { 4841 const PetscInt point = mesh->supports[off + c]; 4842 4843 for (m = 0; m < joinSize; ++m) { 4844 if (point == join[i][m]) { 4845 join[1 - i][newJoinSize++] = point; 4846 break; 4847 } 4848 } 4849 } 4850 joinSize = newJoinSize; 4851 i = 1 - i; 4852 } 4853 *numCoveredPoints = joinSize; 4854 *coveredPoints = join[i]; 4855 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4856 PetscFunctionReturn(PETSC_SUCCESS); 4857 } 4858 4859 /*@C 4860 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4861 4862 Not Collective 4863 4864 Input Parameters: 4865 + dm - The `DMPLEX` object 4866 . numPoints - The number of input points for the join 4867 - points - The input points 4868 4869 Output Parameters: 4870 + numCoveredPoints - The number of points in the join 4871 - coveredPoints - The points in the join 4872 4873 Level: intermediate 4874 4875 Fortran Notes: 4876 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4877 4878 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4879 @*/ 4880 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4881 { 4882 PetscFunctionBegin; 4883 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4884 if (points) PetscAssertPointer(points, 3); 4885 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4886 PetscAssertPointer(coveredPoints, 5); 4887 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4888 if (numCoveredPoints) *numCoveredPoints = 0; 4889 PetscFunctionReturn(PETSC_SUCCESS); 4890 } 4891 4892 /*@C 4893 DMPlexGetFullJoin - Get an array for the join of the set of points 4894 4895 Not Collective 4896 4897 Input Parameters: 4898 + dm - The `DMPLEX` object 4899 . numPoints - The number of input points for the join 4900 - points - The input points, its length is `numPoints` 4901 4902 Output Parameters: 4903 + numCoveredPoints - The number of points in the join 4904 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4905 4906 Level: intermediate 4907 4908 Fortran Notes: 4909 `points` and `converedPoints` must be declared with 4910 .vb 4911 PetscInt, pointer :: points(:) 4912 PetscInt, pointer :: coveredPints(:) 4913 .ve 4914 4915 The `numCoveredPoints` argument is not present in the Fortran binding. 4916 4917 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4918 @*/ 4919 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4920 { 4921 PetscInt *offsets, **closures; 4922 PetscInt *join[2]; 4923 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4924 PetscInt p, d, c, m, ms; 4925 4926 PetscFunctionBegin; 4927 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4928 PetscAssertPointer(points, 3); 4929 PetscAssertPointer(numCoveredPoints, 4); 4930 PetscAssertPointer(coveredPoints, 5); 4931 4932 PetscCall(DMPlexGetDepth(dm, &depth)); 4933 PetscCall(PetscCalloc1(numPoints, &closures)); 4934 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4935 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4936 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4937 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4938 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4939 4940 for (p = 0; p < numPoints; ++p) { 4941 PetscInt closureSize; 4942 4943 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4944 4945 offsets[p * (depth + 2) + 0] = 0; 4946 for (d = 0; d < depth + 1; ++d) { 4947 PetscInt pStart, pEnd, i; 4948 4949 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4950 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4951 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4952 offsets[p * (depth + 2) + d + 1] = i; 4953 break; 4954 } 4955 } 4956 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4957 } 4958 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); 4959 } 4960 for (d = 0; d < depth + 1; ++d) { 4961 PetscInt dof; 4962 4963 /* Copy in support of first point */ 4964 dof = offsets[d + 1] - offsets[d]; 4965 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4966 /* Check each successive cone */ 4967 for (p = 1; p < numPoints && joinSize; ++p) { 4968 PetscInt newJoinSize = 0; 4969 4970 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4971 for (c = 0; c < dof; ++c) { 4972 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4973 4974 for (m = 0; m < joinSize; ++m) { 4975 if (point == join[i][m]) { 4976 join[1 - i][newJoinSize++] = point; 4977 break; 4978 } 4979 } 4980 } 4981 joinSize = newJoinSize; 4982 i = 1 - i; 4983 } 4984 if (joinSize) break; 4985 } 4986 *numCoveredPoints = joinSize; 4987 *coveredPoints = join[i]; 4988 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4989 PetscCall(PetscFree(closures)); 4990 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4991 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4992 PetscFunctionReturn(PETSC_SUCCESS); 4993 } 4994 4995 /*@C 4996 DMPlexGetMeet - Get an array for the meet of the set of points 4997 4998 Not Collective 4999 5000 Input Parameters: 5001 + dm - The `DMPLEX` object 5002 . numPoints - The number of input points for the meet 5003 - points - The input points, of length `numPoints` 5004 5005 Output Parameters: 5006 + numCoveringPoints - The number of points in the meet 5007 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5008 5009 Level: intermediate 5010 5011 Note: 5012 Currently, this is restricted to a single level meet 5013 5014 Fortran Notes: 5015 `coveringPoints` must be declared with 5016 .vb 5017 PetscInt, pointer :: coveringPoints(:) 5018 .ve 5019 5020 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5021 5022 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5023 @*/ 5024 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5025 { 5026 DM_Plex *mesh = (DM_Plex *)dm->data; 5027 PetscInt *meet[2]; 5028 PetscInt meetSize, i = 0; 5029 PetscInt dof, off, p, c, m; 5030 PetscInt maxConeSize; 5031 5032 PetscFunctionBegin; 5033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5034 PetscAssertPointer(points, 3); 5035 PetscAssertPointer(numCoveringPoints, 4); 5036 PetscAssertPointer(coveringPoints, 5); 5037 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5038 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5039 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5040 /* Copy in cone of first point */ 5041 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5042 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5043 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5044 /* Check each successive cone */ 5045 for (p = 1; p < numPoints; ++p) { 5046 PetscInt newMeetSize = 0; 5047 5048 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5049 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5050 for (c = 0; c < dof; ++c) { 5051 const PetscInt point = mesh->cones[off + c]; 5052 5053 for (m = 0; m < meetSize; ++m) { 5054 if (point == meet[i][m]) { 5055 meet[1 - i][newMeetSize++] = point; 5056 break; 5057 } 5058 } 5059 } 5060 meetSize = newMeetSize; 5061 i = 1 - i; 5062 } 5063 *numCoveringPoints = meetSize; 5064 *coveringPoints = meet[i]; 5065 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5066 PetscFunctionReturn(PETSC_SUCCESS); 5067 } 5068 5069 /*@C 5070 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5071 5072 Not Collective 5073 5074 Input Parameters: 5075 + dm - The `DMPLEX` object 5076 . numPoints - The number of input points for the meet 5077 - points - The input points 5078 5079 Output Parameters: 5080 + numCoveredPoints - The number of points in the meet 5081 - coveredPoints - The points in the meet 5082 5083 Level: intermediate 5084 5085 Fortran Notes: 5086 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5087 5088 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5089 @*/ 5090 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5091 { 5092 PetscFunctionBegin; 5093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5094 if (points) PetscAssertPointer(points, 3); 5095 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5096 PetscAssertPointer(coveredPoints, 5); 5097 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5098 if (numCoveredPoints) *numCoveredPoints = 0; 5099 PetscFunctionReturn(PETSC_SUCCESS); 5100 } 5101 5102 /*@C 5103 DMPlexGetFullMeet - Get an array for the meet of the set of points 5104 5105 Not Collective 5106 5107 Input Parameters: 5108 + dm - The `DMPLEX` object 5109 . numPoints - The number of input points for the meet 5110 - points - The input points, of length `numPoints` 5111 5112 Output Parameters: 5113 + numCoveredPoints - The number of points in the meet 5114 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5115 5116 Level: intermediate 5117 5118 Fortran Notes: 5119 `points` and `coveredPoints` must be declared with 5120 .vb 5121 PetscInt, pointer :: points(:) 5122 PetscInt, pointer :: coveredPoints(:) 5123 .ve 5124 5125 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5126 5127 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5128 @*/ 5129 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5130 { 5131 PetscInt *offsets, **closures; 5132 PetscInt *meet[2]; 5133 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5134 PetscInt p, h, c, m, mc; 5135 5136 PetscFunctionBegin; 5137 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5138 PetscAssertPointer(points, 3); 5139 PetscAssertPointer(numCoveredPoints, 4); 5140 PetscAssertPointer(coveredPoints, 5); 5141 5142 PetscCall(DMPlexGetDepth(dm, &height)); 5143 PetscCall(PetscMalloc1(numPoints, &closures)); 5144 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5145 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5146 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5147 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5148 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5149 5150 for (p = 0; p < numPoints; ++p) { 5151 PetscInt closureSize; 5152 5153 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5154 5155 offsets[p * (height + 2) + 0] = 0; 5156 for (h = 0; h < height + 1; ++h) { 5157 PetscInt pStart, pEnd, i; 5158 5159 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5160 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5161 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5162 offsets[p * (height + 2) + h + 1] = i; 5163 break; 5164 } 5165 } 5166 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5167 } 5168 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); 5169 } 5170 for (h = 0; h < height + 1; ++h) { 5171 PetscInt dof; 5172 5173 /* Copy in cone of first point */ 5174 dof = offsets[h + 1] - offsets[h]; 5175 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5176 /* Check each successive cone */ 5177 for (p = 1; p < numPoints && meetSize; ++p) { 5178 PetscInt newMeetSize = 0; 5179 5180 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5181 for (c = 0; c < dof; ++c) { 5182 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5183 5184 for (m = 0; m < meetSize; ++m) { 5185 if (point == meet[i][m]) { 5186 meet[1 - i][newMeetSize++] = point; 5187 break; 5188 } 5189 } 5190 } 5191 meetSize = newMeetSize; 5192 i = 1 - i; 5193 } 5194 if (meetSize) break; 5195 } 5196 *numCoveredPoints = meetSize; 5197 *coveredPoints = meet[i]; 5198 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5199 PetscCall(PetscFree(closures)); 5200 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5201 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5202 PetscFunctionReturn(PETSC_SUCCESS); 5203 } 5204 5205 /*@ 5206 DMPlexEqual - Determine if two `DM` have the same topology 5207 5208 Not Collective 5209 5210 Input Parameters: 5211 + dmA - A `DMPLEX` object 5212 - dmB - A `DMPLEX` object 5213 5214 Output Parameter: 5215 . equal - `PETSC_TRUE` if the topologies are identical 5216 5217 Level: intermediate 5218 5219 Note: 5220 We are not solving graph isomorphism, so we do not permute. 5221 5222 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5223 @*/ 5224 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5225 { 5226 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5227 5228 PetscFunctionBegin; 5229 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5230 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5231 PetscAssertPointer(equal, 3); 5232 5233 *equal = PETSC_FALSE; 5234 PetscCall(DMPlexGetDepth(dmA, &depth)); 5235 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5236 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5237 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5238 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5239 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5240 for (p = pStart; p < pEnd; ++p) { 5241 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5242 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5243 5244 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5245 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5246 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5247 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5248 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5249 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5250 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5251 for (c = 0; c < coneSize; ++c) { 5252 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5253 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5254 } 5255 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5256 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5257 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5258 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5259 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5260 for (s = 0; s < supportSize; ++s) { 5261 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5262 } 5263 } 5264 *equal = PETSC_TRUE; 5265 PetscFunctionReturn(PETSC_SUCCESS); 5266 } 5267 5268 /*@ 5269 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5270 5271 Not Collective 5272 5273 Input Parameters: 5274 + dm - The `DMPLEX` 5275 . cellDim - The cell dimension 5276 - numCorners - The number of vertices on a cell 5277 5278 Output Parameter: 5279 . numFaceVertices - The number of vertices on a face 5280 5281 Level: developer 5282 5283 Note: 5284 Of course this can only work for a restricted set of symmetric shapes 5285 5286 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5287 @*/ 5288 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5289 { 5290 MPI_Comm comm; 5291 5292 PetscFunctionBegin; 5293 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5294 PetscAssertPointer(numFaceVertices, 4); 5295 switch (cellDim) { 5296 case 0: 5297 *numFaceVertices = 0; 5298 break; 5299 case 1: 5300 *numFaceVertices = 1; 5301 break; 5302 case 2: 5303 switch (numCorners) { 5304 case 3: /* triangle */ 5305 *numFaceVertices = 2; /* Edge has 2 vertices */ 5306 break; 5307 case 4: /* quadrilateral */ 5308 *numFaceVertices = 2; /* Edge has 2 vertices */ 5309 break; 5310 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5311 *numFaceVertices = 3; /* Edge has 3 vertices */ 5312 break; 5313 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5314 *numFaceVertices = 3; /* Edge has 3 vertices */ 5315 break; 5316 default: 5317 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5318 } 5319 break; 5320 case 3: 5321 switch (numCorners) { 5322 case 4: /* tetradehdron */ 5323 *numFaceVertices = 3; /* Face has 3 vertices */ 5324 break; 5325 case 6: /* tet cohesive cells */ 5326 *numFaceVertices = 4; /* Face has 4 vertices */ 5327 break; 5328 case 8: /* hexahedron */ 5329 *numFaceVertices = 4; /* Face has 4 vertices */ 5330 break; 5331 case 9: /* tet cohesive Lagrange cells */ 5332 *numFaceVertices = 6; /* Face has 6 vertices */ 5333 break; 5334 case 10: /* quadratic tetrahedron */ 5335 *numFaceVertices = 6; /* Face has 6 vertices */ 5336 break; 5337 case 12: /* hex cohesive Lagrange cells */ 5338 *numFaceVertices = 6; /* Face has 6 vertices */ 5339 break; 5340 case 18: /* quadratic tet cohesive Lagrange cells */ 5341 *numFaceVertices = 6; /* Face has 6 vertices */ 5342 break; 5343 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5344 *numFaceVertices = 9; /* Face has 9 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 default: 5351 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5352 } 5353 PetscFunctionReturn(PETSC_SUCCESS); 5354 } 5355 5356 /*@ 5357 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5358 5359 Not Collective 5360 5361 Input Parameter: 5362 . dm - The `DMPLEX` object 5363 5364 Output Parameter: 5365 . depthLabel - The `DMLabel` recording point depth 5366 5367 Level: developer 5368 5369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5370 @*/ 5371 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5372 { 5373 PetscFunctionBegin; 5374 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5375 PetscAssertPointer(depthLabel, 2); 5376 *depthLabel = dm->depthLabel; 5377 PetscFunctionReturn(PETSC_SUCCESS); 5378 } 5379 5380 /*@ 5381 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5382 5383 Not Collective 5384 5385 Input Parameter: 5386 . dm - The `DMPLEX` object 5387 5388 Output Parameter: 5389 . depth - The number of strata (breadth first levels) in the DAG 5390 5391 Level: developer 5392 5393 Notes: 5394 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5395 5396 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5397 5398 An empty mesh gives -1. 5399 5400 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5401 @*/ 5402 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5403 { 5404 DM_Plex *mesh = (DM_Plex *)dm->data; 5405 DMLabel label; 5406 PetscInt d = -1; 5407 5408 PetscFunctionBegin; 5409 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5410 PetscAssertPointer(depth, 2); 5411 if (mesh->tr) { 5412 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5413 } else { 5414 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5415 // Allow missing depths 5416 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5417 *depth = d; 5418 } 5419 PetscFunctionReturn(PETSC_SUCCESS); 5420 } 5421 5422 /*@ 5423 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5424 5425 Not Collective 5426 5427 Input Parameters: 5428 + dm - The `DMPLEX` object 5429 - depth - The requested depth 5430 5431 Output Parameters: 5432 + start - The first point at this `depth` 5433 - end - One beyond the last point at this `depth` 5434 5435 Level: developer 5436 5437 Notes: 5438 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5439 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5440 higher dimension, e.g., "edges". 5441 5442 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5443 @*/ 5444 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5445 { 5446 DM_Plex *mesh = (DM_Plex *)dm->data; 5447 DMLabel label; 5448 PetscInt pStart, pEnd; 5449 5450 PetscFunctionBegin; 5451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5452 if (start) { 5453 PetscAssertPointer(start, 3); 5454 *start = 0; 5455 } 5456 if (end) { 5457 PetscAssertPointer(end, 4); 5458 *end = 0; 5459 } 5460 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5461 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5462 if (depth < 0) { 5463 if (start) *start = pStart; 5464 if (end) *end = pEnd; 5465 PetscFunctionReturn(PETSC_SUCCESS); 5466 } 5467 if (mesh->tr) { 5468 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5469 } else { 5470 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5471 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5472 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5473 } 5474 PetscFunctionReturn(PETSC_SUCCESS); 5475 } 5476 5477 /*@ 5478 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5479 5480 Not Collective 5481 5482 Input Parameters: 5483 + dm - The `DMPLEX` object 5484 - height - The requested height 5485 5486 Output Parameters: 5487 + start - The first point at this `height` 5488 - end - One beyond the last point at this `height` 5489 5490 Level: developer 5491 5492 Notes: 5493 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5494 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5495 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5496 5497 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5498 @*/ 5499 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5500 { 5501 DMLabel label; 5502 PetscInt depth, pStart, pEnd; 5503 5504 PetscFunctionBegin; 5505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5506 if (start) { 5507 PetscAssertPointer(start, 3); 5508 *start = 0; 5509 } 5510 if (end) { 5511 PetscAssertPointer(end, 4); 5512 *end = 0; 5513 } 5514 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5515 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5516 if (height < 0) { 5517 if (start) *start = pStart; 5518 if (end) *end = pEnd; 5519 PetscFunctionReturn(PETSC_SUCCESS); 5520 } 5521 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5522 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5523 else PetscCall(DMGetDimension(dm, &depth)); 5524 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5525 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5526 PetscFunctionReturn(PETSC_SUCCESS); 5527 } 5528 5529 /*@ 5530 DMPlexGetPointDepth - Get the `depth` of a given point 5531 5532 Not Collective 5533 5534 Input Parameters: 5535 + dm - The `DMPLEX` object 5536 - point - The point 5537 5538 Output Parameter: 5539 . depth - The depth of the `point` 5540 5541 Level: intermediate 5542 5543 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5544 @*/ 5545 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5546 { 5547 PetscFunctionBegin; 5548 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5549 PetscAssertPointer(depth, 3); 5550 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5551 PetscFunctionReturn(PETSC_SUCCESS); 5552 } 5553 5554 /*@ 5555 DMPlexGetPointHeight - Get the `height` of a given point 5556 5557 Not Collective 5558 5559 Input Parameters: 5560 + dm - The `DMPLEX` object 5561 - point - The point 5562 5563 Output Parameter: 5564 . height - The height of the `point` 5565 5566 Level: intermediate 5567 5568 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5569 @*/ 5570 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5571 { 5572 PetscInt n, pDepth; 5573 5574 PetscFunctionBegin; 5575 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5576 PetscAssertPointer(height, 3); 5577 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5578 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5579 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5580 PetscFunctionReturn(PETSC_SUCCESS); 5581 } 5582 5583 /*@ 5584 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5585 5586 Not Collective 5587 5588 Input Parameter: 5589 . dm - The `DMPLEX` object 5590 5591 Output Parameter: 5592 . celltypeLabel - The `DMLabel` recording cell polytope type 5593 5594 Level: developer 5595 5596 Note: 5597 This function will trigger automatica computation of cell types. This can be disabled by calling 5598 `DMCreateLabel`(dm, "celltype") beforehand. 5599 5600 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5601 @*/ 5602 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5603 { 5604 PetscFunctionBegin; 5605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5606 PetscAssertPointer(celltypeLabel, 2); 5607 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5608 *celltypeLabel = dm->celltypeLabel; 5609 PetscFunctionReturn(PETSC_SUCCESS); 5610 } 5611 5612 /*@ 5613 DMPlexGetCellType - Get the polytope type of a given cell 5614 5615 Not Collective 5616 5617 Input Parameters: 5618 + dm - The `DMPLEX` object 5619 - cell - The cell 5620 5621 Output Parameter: 5622 . celltype - The polytope type of the cell 5623 5624 Level: intermediate 5625 5626 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5627 @*/ 5628 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5629 { 5630 DM_Plex *mesh = (DM_Plex *)dm->data; 5631 DMLabel label; 5632 PetscInt ct; 5633 5634 PetscFunctionBegin; 5635 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5636 PetscAssertPointer(celltype, 3); 5637 if (mesh->tr) { 5638 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5639 } else { 5640 PetscInt pStart, pEnd; 5641 5642 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5643 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5644 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5645 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5646 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5647 for (PetscInt p = pStart; p < pEnd; p++) { 5648 PetscCall(DMLabelGetValue(label, p, &ct)); 5649 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5650 } 5651 } 5652 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5653 if (PetscDefined(USE_DEBUG)) { 5654 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5655 PetscCall(DMLabelGetValue(label, cell, &ct)); 5656 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5657 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5658 } 5659 } 5660 PetscFunctionReturn(PETSC_SUCCESS); 5661 } 5662 5663 /*@ 5664 DMPlexSetCellType - Set the polytope type of a given cell 5665 5666 Not Collective 5667 5668 Input Parameters: 5669 + dm - The `DMPLEX` object 5670 . cell - The cell 5671 - celltype - The polytope type of the cell 5672 5673 Level: advanced 5674 5675 Note: 5676 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5677 is executed. This function will override the computed type. However, if automatic classification will not succeed 5678 and a user wants to manually specify all types, the classification must be disabled by calling 5679 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5680 5681 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5682 @*/ 5683 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5684 { 5685 DM_Plex *mesh = (DM_Plex *)dm->data; 5686 DMLabel label; 5687 PetscInt pStart, pEnd; 5688 5689 PetscFunctionBegin; 5690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5691 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5692 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5693 PetscCall(DMLabelSetValue(label, cell, celltype)); 5694 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5695 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5696 PetscFunctionReturn(PETSC_SUCCESS); 5697 } 5698 5699 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5700 { 5701 PetscSection section; 5702 PetscInt maxHeight; 5703 const char *prefix; 5704 5705 PetscFunctionBegin; 5706 PetscCall(DMClone(dm, cdm)); 5707 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5708 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5709 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5710 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5711 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5712 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5713 PetscCall(DMSetLocalSection(*cdm, section)); 5714 PetscCall(PetscSectionDestroy(§ion)); 5715 5716 PetscCall(DMSetNumFields(*cdm, 1)); 5717 PetscCall(DMCreateDS(*cdm)); 5718 (*cdm)->cloneOpts = PETSC_TRUE; 5719 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5720 PetscFunctionReturn(PETSC_SUCCESS); 5721 } 5722 5723 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5724 { 5725 Vec coordsLocal, cellCoordsLocal; 5726 DM coordsDM, cellCoordsDM; 5727 5728 PetscFunctionBegin; 5729 *field = NULL; 5730 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5731 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5732 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5733 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5734 if (coordsLocal && coordsDM) { 5735 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5736 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5737 } 5738 PetscFunctionReturn(PETSC_SUCCESS); 5739 } 5740 5741 /*@ 5742 DMPlexGetConeSection - Return a section which describes the layout of cone data 5743 5744 Not Collective 5745 5746 Input Parameter: 5747 . dm - The `DMPLEX` object 5748 5749 Output Parameter: 5750 . section - The `PetscSection` object 5751 5752 Level: developer 5753 5754 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5755 @*/ 5756 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5757 { 5758 DM_Plex *mesh = (DM_Plex *)dm->data; 5759 5760 PetscFunctionBegin; 5761 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5762 if (section) *section = mesh->coneSection; 5763 PetscFunctionReturn(PETSC_SUCCESS); 5764 } 5765 5766 /*@ 5767 DMPlexGetSupportSection - Return a section which describes the layout of support data 5768 5769 Not Collective 5770 5771 Input Parameter: 5772 . dm - The `DMPLEX` object 5773 5774 Output Parameter: 5775 . section - The `PetscSection` object 5776 5777 Level: developer 5778 5779 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5780 @*/ 5781 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5782 { 5783 DM_Plex *mesh = (DM_Plex *)dm->data; 5784 5785 PetscFunctionBegin; 5786 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5787 if (section) *section = mesh->supportSection; 5788 PetscFunctionReturn(PETSC_SUCCESS); 5789 } 5790 5791 /*@C 5792 DMPlexGetCones - Return cone data 5793 5794 Not Collective 5795 5796 Input Parameter: 5797 . dm - The `DMPLEX` object 5798 5799 Output Parameter: 5800 . cones - The cone for each point 5801 5802 Level: developer 5803 5804 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5805 @*/ 5806 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5807 { 5808 DM_Plex *mesh = (DM_Plex *)dm->data; 5809 5810 PetscFunctionBegin; 5811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5812 if (cones) *cones = mesh->cones; 5813 PetscFunctionReturn(PETSC_SUCCESS); 5814 } 5815 5816 /*@C 5817 DMPlexGetConeOrientations - Return cone orientation data 5818 5819 Not Collective 5820 5821 Input Parameter: 5822 . dm - The `DMPLEX` object 5823 5824 Output Parameter: 5825 . coneOrientations - The array of cone orientations for all points 5826 5827 Level: developer 5828 5829 Notes: 5830 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5831 as returned by `DMPlexGetConeOrientation()`. 5832 5833 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5834 5835 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5836 @*/ 5837 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5838 { 5839 DM_Plex *mesh = (DM_Plex *)dm->data; 5840 5841 PetscFunctionBegin; 5842 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5843 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5844 PetscFunctionReturn(PETSC_SUCCESS); 5845 } 5846 5847 /* FEM Support */ 5848 5849 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5850 { 5851 PetscInt depth; 5852 5853 PetscFunctionBegin; 5854 PetscCall(DMPlexGetDepth(plex, &depth)); 5855 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5856 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5857 PetscFunctionReturn(PETSC_SUCCESS); 5858 } 5859 5860 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5861 { 5862 PetscInt depth; 5863 5864 PetscFunctionBegin; 5865 PetscCall(DMPlexGetDepth(plex, &depth)); 5866 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5867 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5868 PetscFunctionReturn(PETSC_SUCCESS); 5869 } 5870 5871 /* 5872 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5873 representing a line in the section. 5874 */ 5875 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5876 { 5877 PetscObject obj; 5878 PetscClassId id; 5879 PetscFE fe = NULL; 5880 5881 PetscFunctionBeginHot; 5882 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5883 PetscCall(DMGetField(dm, field, NULL, &obj)); 5884 PetscCall(PetscObjectGetClassId(obj, &id)); 5885 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5886 5887 if (!fe) { 5888 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5889 /* An order k SEM disc has k-1 dofs on an edge */ 5890 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5891 *k = *k / *Nc + 1; 5892 } else { 5893 PetscInt dual_space_size, dim; 5894 PetscDualSpace dsp; 5895 5896 PetscCall(DMGetDimension(dm, &dim)); 5897 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5898 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5899 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5900 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5901 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5902 } 5903 PetscFunctionReturn(PETSC_SUCCESS); 5904 } 5905 5906 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5907 { 5908 PetscFunctionBeginHot; 5909 if (tensor) { 5910 *dof = PetscPowInt(k + 1, dim); 5911 } else { 5912 switch (dim) { 5913 case 1: 5914 *dof = k + 1; 5915 break; 5916 case 2: 5917 *dof = ((k + 1) * (k + 2)) / 2; 5918 break; 5919 case 3: 5920 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5921 break; 5922 default: 5923 *dof = 0; 5924 } 5925 } 5926 PetscFunctionReturn(PETSC_SUCCESS); 5927 } 5928 5929 /*@ 5930 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5931 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5932 section provided (or the section of the `DM`). 5933 5934 Input Parameters: 5935 + dm - The `DM` 5936 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5937 - section - The `PetscSection` to reorder, or `NULL` for the default section 5938 5939 Example: 5940 A typical interpolated single-quad mesh might order points as 5941 .vb 5942 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5943 5944 v4 -- e6 -- v3 5945 | | 5946 e7 c0 e8 5947 | | 5948 v1 -- e5 -- v2 5949 .ve 5950 5951 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5952 dofs in the order of points, e.g., 5953 .vb 5954 c0 -> [0,1,2,3] 5955 v1 -> [4] 5956 ... 5957 e5 -> [8, 9] 5958 .ve 5959 5960 which corresponds to the dofs 5961 .vb 5962 6 10 11 7 5963 13 2 3 15 5964 12 0 1 14 5965 4 8 9 5 5966 .ve 5967 5968 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5969 .vb 5970 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5971 .ve 5972 5973 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5974 .vb 5975 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5976 .ve 5977 5978 Level: developer 5979 5980 Notes: 5981 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5982 degree of the basis. 5983 5984 This is required to run with libCEED. 5985 5986 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5987 @*/ 5988 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5989 { 5990 DMLabel label; 5991 PetscInt dim, depth = -1, eStart = -1, Nf; 5992 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5993 5994 PetscFunctionBegin; 5995 PetscCall(DMGetDimension(dm, &dim)); 5996 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5997 if (point < 0) { 5998 PetscInt sStart, sEnd; 5999 6000 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6001 point = sEnd - sStart ? sStart : point; 6002 } 6003 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6004 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6005 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6006 if (depth == 1) { 6007 eStart = point; 6008 } else if (depth == dim) { 6009 const PetscInt *cone; 6010 6011 PetscCall(DMPlexGetCone(dm, point, &cone)); 6012 if (dim == 2) eStart = cone[0]; 6013 else if (dim == 3) { 6014 const PetscInt *cone2; 6015 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6016 eStart = cone2[0]; 6017 } 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); 6018 } 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); 6019 6020 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6021 for (PetscInt d = 1; d <= dim; d++) { 6022 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6023 PetscInt *perm; 6024 6025 for (f = 0; f < Nf; ++f) { 6026 PetscInt dof; 6027 6028 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6029 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6030 if (!continuous && d < dim) continue; 6031 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6032 size += dof * Nc; 6033 } 6034 PetscCall(PetscMalloc1(size, &perm)); 6035 for (f = 0; f < Nf; ++f) { 6036 switch (d) { 6037 case 1: 6038 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6039 if (!continuous && d < dim) continue; 6040 /* 6041 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6042 We want [ vtx0; edge of length k-1; vtx1 ] 6043 */ 6044 if (continuous) { 6045 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6046 for (i = 0; i < k - 1; i++) 6047 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6048 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6049 foffset = offset; 6050 } else { 6051 PetscInt dof; 6052 6053 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6054 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6055 foffset = offset; 6056 } 6057 break; 6058 case 2: 6059 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6060 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6061 if (!continuous && d < dim) continue; 6062 /* The SEM order is 6063 6064 v_lb, {e_b}, v_rb, 6065 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6066 v_lt, reverse {e_t}, v_rt 6067 */ 6068 if (continuous) { 6069 const PetscInt of = 0; 6070 const PetscInt oeb = of + PetscSqr(k - 1); 6071 const PetscInt oer = oeb + (k - 1); 6072 const PetscInt oet = oer + (k - 1); 6073 const PetscInt oel = oet + (k - 1); 6074 const PetscInt ovlb = oel + (k - 1); 6075 const PetscInt ovrb = ovlb + 1; 6076 const PetscInt ovrt = ovrb + 1; 6077 const PetscInt ovlt = ovrt + 1; 6078 PetscInt o; 6079 6080 /* bottom */ 6081 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6082 for (o = oeb; o < oer; ++o) 6083 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6084 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6085 /* middle */ 6086 for (i = 0; i < k - 1; ++i) { 6087 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6088 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6089 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6090 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6091 } 6092 /* top */ 6093 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6094 for (o = oel - 1; o >= oet; --o) 6095 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6096 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6097 foffset = offset; 6098 } else { 6099 PetscInt dof; 6100 6101 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6102 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6103 foffset = offset; 6104 } 6105 break; 6106 case 3: 6107 /* The original hex closure is 6108 6109 {c, 6110 f_b, f_t, f_f, f_b, f_r, f_l, 6111 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6112 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6113 */ 6114 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6115 if (!continuous && d < dim) continue; 6116 /* The SEM order is 6117 Bottom Slice 6118 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6119 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6120 v_blb, {e_bb}, v_brb, 6121 6122 Middle Slice (j) 6123 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6124 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6125 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6126 6127 Top Slice 6128 v_tlf, {e_tf}, v_trf, 6129 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6130 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6131 */ 6132 if (continuous) { 6133 const PetscInt oc = 0; 6134 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6135 const PetscInt oft = ofb + PetscSqr(k - 1); 6136 const PetscInt off = oft + PetscSqr(k - 1); 6137 const PetscInt ofk = off + PetscSqr(k - 1); 6138 const PetscInt ofr = ofk + PetscSqr(k - 1); 6139 const PetscInt ofl = ofr + PetscSqr(k - 1); 6140 const PetscInt oebl = ofl + PetscSqr(k - 1); 6141 const PetscInt oebb = oebl + (k - 1); 6142 const PetscInt oebr = oebb + (k - 1); 6143 const PetscInt oebf = oebr + (k - 1); 6144 const PetscInt oetf = oebf + (k - 1); 6145 const PetscInt oetr = oetf + (k - 1); 6146 const PetscInt oetb = oetr + (k - 1); 6147 const PetscInt oetl = oetb + (k - 1); 6148 const PetscInt oerf = oetl + (k - 1); 6149 const PetscInt oelf = oerf + (k - 1); 6150 const PetscInt oelb = oelf + (k - 1); 6151 const PetscInt oerb = oelb + (k - 1); 6152 const PetscInt ovblf = oerb + (k - 1); 6153 const PetscInt ovblb = ovblf + 1; 6154 const PetscInt ovbrb = ovblb + 1; 6155 const PetscInt ovbrf = ovbrb + 1; 6156 const PetscInt ovtlf = ovbrf + 1; 6157 const PetscInt ovtrf = ovtlf + 1; 6158 const PetscInt ovtrb = ovtrf + 1; 6159 const PetscInt ovtlb = ovtrb + 1; 6160 PetscInt o, n; 6161 6162 /* Bottom Slice */ 6163 /* bottom */ 6164 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6165 for (o = oetf - 1; o >= oebf; --o) 6166 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6167 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6168 /* middle */ 6169 for (i = 0; i < k - 1; ++i) { 6170 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6171 for (n = 0; n < k - 1; ++n) { 6172 o = ofb + n * (k - 1) + i; 6173 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6174 } 6175 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6176 } 6177 /* top */ 6178 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6179 for (o = oebb; o < oebr; ++o) 6180 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6181 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6182 6183 /* Middle Slice */ 6184 for (j = 0; j < k - 1; ++j) { 6185 /* bottom */ 6186 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6187 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6188 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6189 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6190 /* middle */ 6191 for (i = 0; i < k - 1; ++i) { 6192 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6193 for (n = 0; n < k - 1; ++n) 6194 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6195 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6196 } 6197 /* top */ 6198 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6199 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --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] = (oerb + (k - 2) - j) * Nc + c + foffset; 6202 } 6203 6204 /* Top Slice */ 6205 /* bottom */ 6206 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6207 for (o = oetf; o < oetr; ++o) 6208 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6209 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6210 /* middle */ 6211 for (i = 0; i < k - 1; ++i) { 6212 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6213 for (n = 0; n < k - 1; ++n) 6214 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6215 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6216 } 6217 /* top */ 6218 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6219 for (o = oetl - 1; o >= oetb; --o) 6220 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6221 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6222 6223 foffset = offset; 6224 } else { 6225 PetscInt dof; 6226 6227 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6228 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6229 foffset = offset; 6230 } 6231 break; 6232 default: 6233 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6234 } 6235 } 6236 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6237 /* Check permutation */ 6238 { 6239 PetscInt *check; 6240 6241 PetscCall(PetscMalloc1(size, &check)); 6242 for (i = 0; i < size; ++i) { 6243 check[i] = -1; 6244 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6245 } 6246 for (i = 0; i < size; ++i) check[perm[i]] = i; 6247 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6248 PetscCall(PetscFree(check)); 6249 } 6250 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6251 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6252 PetscInt *loc_perm; 6253 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6254 for (PetscInt i = 0; i < size; i++) { 6255 loc_perm[i] = perm[i]; 6256 loc_perm[size + i] = size + perm[i]; 6257 } 6258 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6259 } 6260 } 6261 PetscFunctionReturn(PETSC_SUCCESS); 6262 } 6263 6264 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6265 { 6266 PetscDS prob; 6267 PetscInt depth, Nf, h; 6268 DMLabel label; 6269 6270 PetscFunctionBeginHot; 6271 PetscCall(DMGetDS(dm, &prob)); 6272 Nf = prob->Nf; 6273 label = dm->depthLabel; 6274 *dspace = NULL; 6275 if (field < Nf) { 6276 PetscObject disc = prob->disc[field]; 6277 6278 if (disc->classid == PETSCFE_CLASSID) { 6279 PetscDualSpace dsp; 6280 6281 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6282 PetscCall(DMLabelGetNumValues(label, &depth)); 6283 PetscCall(DMLabelGetValue(label, point, &h)); 6284 h = depth - 1 - h; 6285 if (h) { 6286 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6287 } else { 6288 *dspace = dsp; 6289 } 6290 } 6291 } 6292 PetscFunctionReturn(PETSC_SUCCESS); 6293 } 6294 6295 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6296 { 6297 PetscScalar *array; 6298 const PetscScalar *vArray; 6299 const PetscInt *cone, *coneO; 6300 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6301 6302 PetscFunctionBeginHot; 6303 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6304 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6305 PetscCall(DMPlexGetCone(dm, point, &cone)); 6306 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6307 if (!values || !*values) { 6308 if ((point >= pStart) && (point < pEnd)) { 6309 PetscInt dof; 6310 6311 PetscCall(PetscSectionGetDof(section, point, &dof)); 6312 size += dof; 6313 } 6314 for (p = 0; p < numPoints; ++p) { 6315 const PetscInt cp = cone[p]; 6316 PetscInt dof; 6317 6318 if ((cp < pStart) || (cp >= pEnd)) continue; 6319 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6320 size += dof; 6321 } 6322 if (!values) { 6323 if (csize) *csize = size; 6324 PetscFunctionReturn(PETSC_SUCCESS); 6325 } 6326 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6327 } else { 6328 array = *values; 6329 } 6330 size = 0; 6331 PetscCall(VecGetArrayRead(v, &vArray)); 6332 if ((point >= pStart) && (point < pEnd)) { 6333 PetscInt dof, off, d; 6334 const PetscScalar *varr; 6335 6336 PetscCall(PetscSectionGetDof(section, point, &dof)); 6337 PetscCall(PetscSectionGetOffset(section, point, &off)); 6338 varr = PetscSafePointerPlusOffset(vArray, off); 6339 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6340 size += dof; 6341 } 6342 for (p = 0; p < numPoints; ++p) { 6343 const PetscInt cp = cone[p]; 6344 PetscInt o = coneO[p]; 6345 PetscInt dof, off, d; 6346 const PetscScalar *varr; 6347 6348 if ((cp < pStart) || (cp >= pEnd)) continue; 6349 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6350 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6351 varr = PetscSafePointerPlusOffset(vArray, off); 6352 if (o >= 0) { 6353 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6354 } else { 6355 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6356 } 6357 size += dof; 6358 } 6359 PetscCall(VecRestoreArrayRead(v, &vArray)); 6360 if (!*values) { 6361 if (csize) *csize = size; 6362 *values = array; 6363 } else { 6364 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6365 *csize = size; 6366 } 6367 PetscFunctionReturn(PETSC_SUCCESS); 6368 } 6369 6370 /* Compress out points not in the section */ 6371 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6372 { 6373 const PetscInt np = *numPoints; 6374 PetscInt pStart, pEnd, p, q; 6375 6376 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6377 for (p = 0, q = 0; p < np; ++p) { 6378 const PetscInt r = points[p * 2]; 6379 if ((r >= pStart) && (r < pEnd)) { 6380 points[q * 2] = r; 6381 points[q * 2 + 1] = points[p * 2 + 1]; 6382 ++q; 6383 } 6384 } 6385 *numPoints = q; 6386 return PETSC_SUCCESS; 6387 } 6388 6389 /* Compressed closure does not apply closure permutation */ 6390 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6391 { 6392 const PetscInt *cla = NULL; 6393 PetscInt np, *pts = NULL; 6394 6395 PetscFunctionBeginHot; 6396 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6397 if (!ornt && *clPoints) { 6398 PetscInt dof, off; 6399 6400 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6401 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6402 PetscCall(ISGetIndices(*clPoints, &cla)); 6403 np = dof / 2; 6404 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6405 } else { 6406 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6407 PetscCall(CompressPoints_Private(section, &np, pts)); 6408 } 6409 *numPoints = np; 6410 *points = pts; 6411 *clp = cla; 6412 PetscFunctionReturn(PETSC_SUCCESS); 6413 } 6414 6415 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6416 { 6417 PetscFunctionBeginHot; 6418 if (!*clPoints) { 6419 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6420 } else { 6421 PetscCall(ISRestoreIndices(*clPoints, clp)); 6422 } 6423 *numPoints = 0; 6424 *points = NULL; 6425 *clSec = NULL; 6426 *clPoints = NULL; 6427 *clp = NULL; 6428 PetscFunctionReturn(PETSC_SUCCESS); 6429 } 6430 6431 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6432 { 6433 PetscInt offset = 0, p; 6434 const PetscInt **perms = NULL; 6435 const PetscScalar **flips = NULL; 6436 6437 PetscFunctionBeginHot; 6438 *size = 0; 6439 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6440 for (p = 0; p < numPoints; p++) { 6441 const PetscInt point = points[2 * p]; 6442 const PetscInt *perm = perms ? perms[p] : NULL; 6443 const PetscScalar *flip = flips ? flips[p] : NULL; 6444 PetscInt dof, off, d; 6445 const PetscScalar *varr; 6446 6447 PetscCall(PetscSectionGetDof(section, point, &dof)); 6448 PetscCall(PetscSectionGetOffset(section, point, &off)); 6449 varr = PetscSafePointerPlusOffset(vArray, off); 6450 if (clperm) { 6451 if (perm) { 6452 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6453 } else { 6454 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6455 } 6456 if (flip) { 6457 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6458 } 6459 } else { 6460 if (perm) { 6461 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6462 } else { 6463 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6464 } 6465 if (flip) { 6466 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6467 } 6468 } 6469 offset += dof; 6470 } 6471 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6472 *size = offset; 6473 PetscFunctionReturn(PETSC_SUCCESS); 6474 } 6475 6476 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[]) 6477 { 6478 PetscInt offset = 0, f; 6479 6480 PetscFunctionBeginHot; 6481 *size = 0; 6482 for (f = 0; f < numFields; ++f) { 6483 PetscInt p; 6484 const PetscInt **perms = NULL; 6485 const PetscScalar **flips = NULL; 6486 6487 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6488 for (p = 0; p < numPoints; p++) { 6489 const PetscInt point = points[2 * p]; 6490 PetscInt fdof, foff, b; 6491 const PetscScalar *varr; 6492 const PetscInt *perm = perms ? perms[p] : NULL; 6493 const PetscScalar *flip = flips ? flips[p] : NULL; 6494 6495 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6496 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6497 varr = &vArray[foff]; 6498 if (clperm) { 6499 if (perm) { 6500 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6501 } else { 6502 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6503 } 6504 if (flip) { 6505 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6506 } 6507 } else { 6508 if (perm) { 6509 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6510 } else { 6511 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6512 } 6513 if (flip) { 6514 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6515 } 6516 } 6517 offset += fdof; 6518 } 6519 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6520 } 6521 *size = offset; 6522 PetscFunctionReturn(PETSC_SUCCESS); 6523 } 6524 6525 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6526 { 6527 PetscSection clSection; 6528 IS clPoints; 6529 PetscInt *points = NULL; 6530 const PetscInt *clp, *perm = NULL; 6531 PetscInt depth, numFields, numPoints, asize; 6532 6533 PetscFunctionBeginHot; 6534 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6535 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6536 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6537 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6538 PetscCall(DMPlexGetDepth(dm, &depth)); 6539 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6540 if (depth == 1 && numFields < 2) { 6541 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6542 PetscFunctionReturn(PETSC_SUCCESS); 6543 } 6544 /* Get points */ 6545 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6546 /* Get sizes */ 6547 asize = 0; 6548 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6549 PetscInt dof; 6550 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6551 asize += dof; 6552 } 6553 if (values) { 6554 const PetscScalar *vArray; 6555 PetscInt size; 6556 6557 if (*values) { 6558 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); 6559 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6560 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6561 PetscCall(VecGetArrayRead(v, &vArray)); 6562 /* Get values */ 6563 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6564 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6565 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6566 /* Cleanup array */ 6567 PetscCall(VecRestoreArrayRead(v, &vArray)); 6568 } 6569 if (csize) *csize = asize; 6570 /* Cleanup points */ 6571 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6572 PetscFunctionReturn(PETSC_SUCCESS); 6573 } 6574 6575 /*@C 6576 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6577 6578 Not collective 6579 6580 Input Parameters: 6581 + dm - The `DM` 6582 . section - The section describing the layout in `v`, or `NULL` to use the default section 6583 . v - The local vector 6584 - point - The point in the `DM` 6585 6586 Input/Output Parameters: 6587 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6588 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6589 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6590 6591 Level: intermediate 6592 6593 Notes: 6594 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6595 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6596 assembly function, and a user may already have allocated storage for this operation. 6597 6598 A typical use could be 6599 .vb 6600 values = NULL; 6601 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6602 for (cl = 0; cl < clSize; ++cl) { 6603 <Compute on closure> 6604 } 6605 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6606 .ve 6607 or 6608 .vb 6609 PetscMalloc1(clMaxSize, &values); 6610 for (p = pStart; p < pEnd; ++p) { 6611 clSize = clMaxSize; 6612 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6613 for (cl = 0; cl < clSize; ++cl) { 6614 <Compute on closure> 6615 } 6616 } 6617 PetscFree(values); 6618 .ve 6619 6620 Fortran Notes: 6621 The `csize` argument is not present in the Fortran binding. 6622 6623 `values` must be declared with 6624 .vb 6625 PetscScalar,dimension(:),pointer :: values 6626 .ve 6627 and it will be allocated internally by PETSc to hold the values returned 6628 6629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6630 @*/ 6631 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6632 { 6633 PetscFunctionBeginHot; 6634 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6635 PetscFunctionReturn(PETSC_SUCCESS); 6636 } 6637 6638 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6639 { 6640 DMLabel depthLabel; 6641 PetscSection clSection; 6642 IS clPoints; 6643 PetscScalar *array; 6644 const PetscScalar *vArray; 6645 PetscInt *points = NULL; 6646 const PetscInt *clp, *perm = NULL; 6647 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6648 6649 PetscFunctionBeginHot; 6650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6651 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6652 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6653 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6654 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6655 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6656 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6657 if (mdepth == 1 && numFields < 2) { 6658 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6659 PetscFunctionReturn(PETSC_SUCCESS); 6660 } 6661 /* Get points */ 6662 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6663 for (clsize = 0, p = 0; p < Np; p++) { 6664 PetscInt dof; 6665 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6666 clsize += dof; 6667 } 6668 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6669 /* Filter points */ 6670 for (p = 0; p < numPoints * 2; p += 2) { 6671 PetscInt dep; 6672 6673 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6674 if (dep != depth) continue; 6675 points[Np * 2 + 0] = points[p]; 6676 points[Np * 2 + 1] = points[p + 1]; 6677 ++Np; 6678 } 6679 /* Get array */ 6680 if (!values || !*values) { 6681 PetscInt asize = 0, dof; 6682 6683 for (p = 0; p < Np * 2; p += 2) { 6684 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6685 asize += dof; 6686 } 6687 if (!values) { 6688 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6689 if (csize) *csize = asize; 6690 PetscFunctionReturn(PETSC_SUCCESS); 6691 } 6692 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6693 } else { 6694 array = *values; 6695 } 6696 PetscCall(VecGetArrayRead(v, &vArray)); 6697 /* Get values */ 6698 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6699 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6700 /* Cleanup points */ 6701 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6702 /* Cleanup array */ 6703 PetscCall(VecRestoreArrayRead(v, &vArray)); 6704 if (!*values) { 6705 if (csize) *csize = size; 6706 *values = array; 6707 } else { 6708 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6709 *csize = size; 6710 } 6711 PetscFunctionReturn(PETSC_SUCCESS); 6712 } 6713 6714 /*@C 6715 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6716 6717 Not collective 6718 6719 Input Parameters: 6720 + dm - The `DM` 6721 . section - The section describing the layout in `v`, or `NULL` to use the default section 6722 . v - The local vector 6723 . point - The point in the `DM` 6724 . csize - The number of values in the closure, or `NULL` 6725 - values - The array of values 6726 6727 Level: intermediate 6728 6729 Note: 6730 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6731 6732 Fortran Note: 6733 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6734 6735 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6736 @*/ 6737 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6738 { 6739 PetscInt size = 0; 6740 6741 PetscFunctionBegin; 6742 /* Should work without recalculating size */ 6743 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6744 *values = NULL; 6745 PetscFunctionReturn(PETSC_SUCCESS); 6746 } 6747 6748 static inline void add(PetscScalar *x, PetscScalar y) 6749 { 6750 *x += y; 6751 } 6752 static inline void insert(PetscScalar *x, PetscScalar y) 6753 { 6754 *x = y; 6755 } 6756 6757 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[]) 6758 { 6759 PetscInt cdof; /* The number of constraints on this point */ 6760 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6761 PetscScalar *a; 6762 PetscInt off, cind = 0, k; 6763 6764 PetscFunctionBegin; 6765 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6766 PetscCall(PetscSectionGetOffset(section, point, &off)); 6767 a = &array[off]; 6768 if (!cdof || setBC) { 6769 if (clperm) { 6770 if (perm) { 6771 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6772 } else { 6773 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6774 } 6775 } else { 6776 if (perm) { 6777 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6778 } else { 6779 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6780 } 6781 } 6782 } else { 6783 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6784 if (clperm) { 6785 if (perm) { 6786 for (k = 0; k < dof; ++k) { 6787 if ((cind < cdof) && (k == cdofs[cind])) { 6788 ++cind; 6789 continue; 6790 } 6791 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6792 } 6793 } else { 6794 for (k = 0; k < dof; ++k) { 6795 if ((cind < cdof) && (k == cdofs[cind])) { 6796 ++cind; 6797 continue; 6798 } 6799 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6800 } 6801 } 6802 } else { 6803 if (perm) { 6804 for (k = 0; k < dof; ++k) { 6805 if ((cind < cdof) && (k == cdofs[cind])) { 6806 ++cind; 6807 continue; 6808 } 6809 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6810 } 6811 } else { 6812 for (k = 0; k < dof; ++k) { 6813 if ((cind < cdof) && (k == cdofs[cind])) { 6814 ++cind; 6815 continue; 6816 } 6817 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6818 } 6819 } 6820 } 6821 } 6822 PetscFunctionReturn(PETSC_SUCCESS); 6823 } 6824 6825 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[]) 6826 { 6827 PetscInt cdof; /* The number of constraints on this point */ 6828 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6829 PetscScalar *a; 6830 PetscInt off, cind = 0, k; 6831 6832 PetscFunctionBegin; 6833 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6834 PetscCall(PetscSectionGetOffset(section, point, &off)); 6835 a = &array[off]; 6836 if (cdof) { 6837 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6838 if (clperm) { 6839 if (perm) { 6840 for (k = 0; k < dof; ++k) { 6841 if ((cind < cdof) && (k == cdofs[cind])) { 6842 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6843 cind++; 6844 } 6845 } 6846 } else { 6847 for (k = 0; k < dof; ++k) { 6848 if ((cind < cdof) && (k == cdofs[cind])) { 6849 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6850 cind++; 6851 } 6852 } 6853 } 6854 } else { 6855 if (perm) { 6856 for (k = 0; k < dof; ++k) { 6857 if ((cind < cdof) && (k == cdofs[cind])) { 6858 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6859 cind++; 6860 } 6861 } 6862 } else { 6863 for (k = 0; k < dof; ++k) { 6864 if ((cind < cdof) && (k == cdofs[cind])) { 6865 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6866 cind++; 6867 } 6868 } 6869 } 6870 } 6871 } 6872 PetscFunctionReturn(PETSC_SUCCESS); 6873 } 6874 6875 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[]) 6876 { 6877 PetscScalar *a; 6878 PetscInt fdof, foff, fcdof, foffset = *offset; 6879 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6880 PetscInt cind = 0, b; 6881 6882 PetscFunctionBegin; 6883 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6884 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6885 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6886 a = &array[foff]; 6887 if (!fcdof || setBC) { 6888 if (clperm) { 6889 if (perm) { 6890 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6891 } else { 6892 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6893 } 6894 } else { 6895 if (perm) { 6896 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6897 } else { 6898 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6899 } 6900 } 6901 } else { 6902 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6903 if (clperm) { 6904 if (perm) { 6905 for (b = 0; b < fdof; b++) { 6906 if ((cind < fcdof) && (b == fcdofs[cind])) { 6907 ++cind; 6908 continue; 6909 } 6910 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6911 } 6912 } else { 6913 for (b = 0; b < fdof; b++) { 6914 if ((cind < fcdof) && (b == fcdofs[cind])) { 6915 ++cind; 6916 continue; 6917 } 6918 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6919 } 6920 } 6921 } else { 6922 if (perm) { 6923 for (b = 0; b < fdof; b++) { 6924 if ((cind < fcdof) && (b == fcdofs[cind])) { 6925 ++cind; 6926 continue; 6927 } 6928 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6929 } 6930 } else { 6931 for (b = 0; b < fdof; b++) { 6932 if ((cind < fcdof) && (b == fcdofs[cind])) { 6933 ++cind; 6934 continue; 6935 } 6936 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6937 } 6938 } 6939 } 6940 } 6941 *offset += fdof; 6942 PetscFunctionReturn(PETSC_SUCCESS); 6943 } 6944 6945 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[]) 6946 { 6947 PetscScalar *a; 6948 PetscInt fdof, foff, fcdof, foffset = *offset; 6949 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6950 PetscInt Nc, cind = 0, ncind = 0, b; 6951 PetscBool ncSet, fcSet; 6952 6953 PetscFunctionBegin; 6954 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6955 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6956 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6957 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6958 a = &array[foff]; 6959 if (fcdof) { 6960 /* We just override fcdof and fcdofs with Ncc and comps */ 6961 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6962 if (clperm) { 6963 if (perm) { 6964 if (comps) { 6965 for (b = 0; b < fdof; b++) { 6966 ncSet = fcSet = PETSC_FALSE; 6967 if (b % Nc == comps[ncind]) { 6968 ncind = (ncind + 1) % Ncc; 6969 ncSet = PETSC_TRUE; 6970 } 6971 if ((cind < fcdof) && (b == fcdofs[cind])) { 6972 ++cind; 6973 fcSet = PETSC_TRUE; 6974 } 6975 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6976 } 6977 } else { 6978 for (b = 0; b < fdof; b++) { 6979 if ((cind < fcdof) && (b == fcdofs[cind])) { 6980 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6981 ++cind; 6982 } 6983 } 6984 } 6985 } else { 6986 if (comps) { 6987 for (b = 0; b < fdof; b++) { 6988 ncSet = fcSet = PETSC_FALSE; 6989 if (b % Nc == comps[ncind]) { 6990 ncind = (ncind + 1) % Ncc; 6991 ncSet = PETSC_TRUE; 6992 } 6993 if ((cind < fcdof) && (b == fcdofs[cind])) { 6994 ++cind; 6995 fcSet = PETSC_TRUE; 6996 } 6997 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6998 } 6999 } else { 7000 for (b = 0; b < fdof; b++) { 7001 if ((cind < fcdof) && (b == fcdofs[cind])) { 7002 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7003 ++cind; 7004 } 7005 } 7006 } 7007 } 7008 } else { 7009 if (perm) { 7010 if (comps) { 7011 for (b = 0; b < fdof; b++) { 7012 ncSet = fcSet = PETSC_FALSE; 7013 if (b % Nc == comps[ncind]) { 7014 ncind = (ncind + 1) % Ncc; 7015 ncSet = PETSC_TRUE; 7016 } 7017 if ((cind < fcdof) && (b == fcdofs[cind])) { 7018 ++cind; 7019 fcSet = PETSC_TRUE; 7020 } 7021 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7022 } 7023 } else { 7024 for (b = 0; b < fdof; b++) { 7025 if ((cind < fcdof) && (b == fcdofs[cind])) { 7026 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7027 ++cind; 7028 } 7029 } 7030 } 7031 } else { 7032 if (comps) { 7033 for (b = 0; b < fdof; b++) { 7034 ncSet = fcSet = PETSC_FALSE; 7035 if (b % Nc == comps[ncind]) { 7036 ncind = (ncind + 1) % Ncc; 7037 ncSet = PETSC_TRUE; 7038 } 7039 if ((cind < fcdof) && (b == fcdofs[cind])) { 7040 ++cind; 7041 fcSet = PETSC_TRUE; 7042 } 7043 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7044 } 7045 } else { 7046 for (b = 0; b < fdof; b++) { 7047 if ((cind < fcdof) && (b == fcdofs[cind])) { 7048 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7049 ++cind; 7050 } 7051 } 7052 } 7053 } 7054 } 7055 } 7056 *offset += fdof; 7057 PetscFunctionReturn(PETSC_SUCCESS); 7058 } 7059 7060 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7061 { 7062 PetscScalar *array; 7063 const PetscInt *cone, *coneO; 7064 PetscInt pStart, pEnd, p, numPoints, off, dof; 7065 7066 PetscFunctionBeginHot; 7067 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7068 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7069 PetscCall(DMPlexGetCone(dm, point, &cone)); 7070 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7071 PetscCall(VecGetArray(v, &array)); 7072 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7073 const PetscInt cp = !p ? point : cone[p - 1]; 7074 const PetscInt o = !p ? 0 : coneO[p - 1]; 7075 7076 if ((cp < pStart) || (cp >= pEnd)) { 7077 dof = 0; 7078 continue; 7079 } 7080 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7081 /* ADD_VALUES */ 7082 { 7083 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7084 PetscScalar *a; 7085 PetscInt cdof, coff, cind = 0, k; 7086 7087 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7088 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7089 a = &array[coff]; 7090 if (!cdof) { 7091 if (o >= 0) { 7092 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7093 } else { 7094 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7095 } 7096 } else { 7097 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7098 if (o >= 0) { 7099 for (k = 0; k < dof; ++k) { 7100 if ((cind < cdof) && (k == cdofs[cind])) { 7101 ++cind; 7102 continue; 7103 } 7104 a[k] += values[off + k]; 7105 } 7106 } else { 7107 for (k = 0; k < dof; ++k) { 7108 if ((cind < cdof) && (k == cdofs[cind])) { 7109 ++cind; 7110 continue; 7111 } 7112 a[k] += values[off + dof - k - 1]; 7113 } 7114 } 7115 } 7116 } 7117 } 7118 PetscCall(VecRestoreArray(v, &array)); 7119 PetscFunctionReturn(PETSC_SUCCESS); 7120 } 7121 7122 /*@C 7123 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7124 7125 Not collective 7126 7127 Input Parameters: 7128 + dm - The `DM` 7129 . section - The section describing the layout in `v`, or `NULL` to use the default section 7130 . v - The local vector 7131 . point - The point in the `DM` 7132 . values - The array of values 7133 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7134 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7135 7136 Level: intermediate 7137 7138 Note: 7139 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7140 7141 Fortran Note: 7142 `values` must be declared with 7143 .vb 7144 PetscScalar,dimension(:),pointer :: values 7145 .ve 7146 7147 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7148 @*/ 7149 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7150 { 7151 PetscSection clSection; 7152 IS clPoints; 7153 PetscScalar *array; 7154 PetscInt *points = NULL; 7155 const PetscInt *clp, *clperm = NULL; 7156 PetscInt depth, numFields, numPoints, p, clsize; 7157 7158 PetscFunctionBeginHot; 7159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7160 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7161 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7162 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7163 PetscCall(DMPlexGetDepth(dm, &depth)); 7164 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7165 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7166 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7167 PetscFunctionReturn(PETSC_SUCCESS); 7168 } 7169 /* Get points */ 7170 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7171 for (clsize = 0, p = 0; p < numPoints; p++) { 7172 PetscInt dof; 7173 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7174 clsize += dof; 7175 } 7176 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7177 /* Get array */ 7178 PetscCall(VecGetArray(v, &array)); 7179 /* Get values */ 7180 if (numFields > 0) { 7181 PetscInt offset = 0, f; 7182 for (f = 0; f < numFields; ++f) { 7183 const PetscInt **perms = NULL; 7184 const PetscScalar **flips = NULL; 7185 7186 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7187 switch (mode) { 7188 case INSERT_VALUES: 7189 for (p = 0; p < numPoints; p++) { 7190 const PetscInt point = points[2 * p]; 7191 const PetscInt *perm = perms ? perms[p] : NULL; 7192 const PetscScalar *flip = flips ? flips[p] : NULL; 7193 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7194 } 7195 break; 7196 case INSERT_ALL_VALUES: 7197 for (p = 0; p < numPoints; p++) { 7198 const PetscInt point = points[2 * p]; 7199 const PetscInt *perm = perms ? perms[p] : NULL; 7200 const PetscScalar *flip = flips ? flips[p] : NULL; 7201 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7202 } 7203 break; 7204 case INSERT_BC_VALUES: 7205 for (p = 0; p < numPoints; p++) { 7206 const PetscInt point = points[2 * p]; 7207 const PetscInt *perm = perms ? perms[p] : NULL; 7208 const PetscScalar *flip = flips ? flips[p] : NULL; 7209 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7210 } 7211 break; 7212 case ADD_VALUES: 7213 for (p = 0; p < numPoints; p++) { 7214 const PetscInt point = points[2 * p]; 7215 const PetscInt *perm = perms ? perms[p] : NULL; 7216 const PetscScalar *flip = flips ? flips[p] : NULL; 7217 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7218 } 7219 break; 7220 case ADD_ALL_VALUES: 7221 for (p = 0; p < numPoints; p++) { 7222 const PetscInt point = points[2 * p]; 7223 const PetscInt *perm = perms ? perms[p] : NULL; 7224 const PetscScalar *flip = flips ? flips[p] : NULL; 7225 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7226 } 7227 break; 7228 case ADD_BC_VALUES: 7229 for (p = 0; p < numPoints; p++) { 7230 const PetscInt point = points[2 * p]; 7231 const PetscInt *perm = perms ? perms[p] : NULL; 7232 const PetscScalar *flip = flips ? flips[p] : NULL; 7233 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7234 } 7235 break; 7236 default: 7237 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7238 } 7239 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7240 } 7241 } else { 7242 PetscInt dof, off; 7243 const PetscInt **perms = NULL; 7244 const PetscScalar **flips = NULL; 7245 7246 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7247 switch (mode) { 7248 case INSERT_VALUES: 7249 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7250 const PetscInt point = points[2 * p]; 7251 const PetscInt *perm = perms ? perms[p] : NULL; 7252 const PetscScalar *flip = flips ? flips[p] : NULL; 7253 PetscCall(PetscSectionGetDof(section, point, &dof)); 7254 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7255 } 7256 break; 7257 case INSERT_ALL_VALUES: 7258 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7259 const PetscInt point = points[2 * p]; 7260 const PetscInt *perm = perms ? perms[p] : NULL; 7261 const PetscScalar *flip = flips ? flips[p] : NULL; 7262 PetscCall(PetscSectionGetDof(section, point, &dof)); 7263 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7264 } 7265 break; 7266 case INSERT_BC_VALUES: 7267 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7268 const PetscInt point = points[2 * p]; 7269 const PetscInt *perm = perms ? perms[p] : NULL; 7270 const PetscScalar *flip = flips ? flips[p] : NULL; 7271 PetscCall(PetscSectionGetDof(section, point, &dof)); 7272 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7273 } 7274 break; 7275 case ADD_VALUES: 7276 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7277 const PetscInt point = points[2 * p]; 7278 const PetscInt *perm = perms ? perms[p] : NULL; 7279 const PetscScalar *flip = flips ? flips[p] : NULL; 7280 PetscCall(PetscSectionGetDof(section, point, &dof)); 7281 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7282 } 7283 break; 7284 case ADD_ALL_VALUES: 7285 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7286 const PetscInt point = points[2 * p]; 7287 const PetscInt *perm = perms ? perms[p] : NULL; 7288 const PetscScalar *flip = flips ? flips[p] : NULL; 7289 PetscCall(PetscSectionGetDof(section, point, &dof)); 7290 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7291 } 7292 break; 7293 case ADD_BC_VALUES: 7294 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7295 const PetscInt point = points[2 * p]; 7296 const PetscInt *perm = perms ? perms[p] : NULL; 7297 const PetscScalar *flip = flips ? flips[p] : NULL; 7298 PetscCall(PetscSectionGetDof(section, point, &dof)); 7299 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7300 } 7301 break; 7302 default: 7303 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7304 } 7305 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7306 } 7307 /* Cleanup points */ 7308 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7309 /* Cleanup array */ 7310 PetscCall(VecRestoreArray(v, &array)); 7311 PetscFunctionReturn(PETSC_SUCCESS); 7312 } 7313 7314 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7315 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7316 { 7317 PetscFunctionBegin; 7318 *contains = PETSC_TRUE; 7319 if (label) { 7320 PetscInt fdof; 7321 7322 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7323 if (!*contains) { 7324 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7325 *offset += fdof; 7326 PetscFunctionReturn(PETSC_SUCCESS); 7327 } 7328 } 7329 PetscFunctionReturn(PETSC_SUCCESS); 7330 } 7331 7332 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7333 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) 7334 { 7335 PetscSection clSection; 7336 IS clPoints; 7337 PetscScalar *array; 7338 PetscInt *points = NULL; 7339 const PetscInt *clp; 7340 PetscInt numFields, numPoints, p; 7341 PetscInt offset = 0, f; 7342 7343 PetscFunctionBeginHot; 7344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7345 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7346 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7347 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7348 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7349 /* Get points */ 7350 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7351 /* Get array */ 7352 PetscCall(VecGetArray(v, &array)); 7353 /* Get values */ 7354 for (f = 0; f < numFields; ++f) { 7355 const PetscInt **perms = NULL; 7356 const PetscScalar **flips = NULL; 7357 PetscBool contains; 7358 7359 if (!fieldActive[f]) { 7360 for (p = 0; p < numPoints * 2; p += 2) { 7361 PetscInt fdof; 7362 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7363 offset += fdof; 7364 } 7365 continue; 7366 } 7367 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7368 switch (mode) { 7369 case INSERT_VALUES: 7370 for (p = 0; p < numPoints; p++) { 7371 const PetscInt point = points[2 * p]; 7372 const PetscInt *perm = perms ? perms[p] : NULL; 7373 const PetscScalar *flip = flips ? flips[p] : NULL; 7374 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7375 if (!contains) continue; 7376 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7377 } 7378 break; 7379 case INSERT_ALL_VALUES: 7380 for (p = 0; p < numPoints; p++) { 7381 const PetscInt point = points[2 * p]; 7382 const PetscInt *perm = perms ? perms[p] : NULL; 7383 const PetscScalar *flip = flips ? flips[p] : NULL; 7384 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7385 if (!contains) continue; 7386 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7387 } 7388 break; 7389 case INSERT_BC_VALUES: 7390 for (p = 0; p < numPoints; p++) { 7391 const PetscInt point = points[2 * p]; 7392 const PetscInt *perm = perms ? perms[p] : NULL; 7393 const PetscScalar *flip = flips ? flips[p] : NULL; 7394 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7395 if (!contains) continue; 7396 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7397 } 7398 break; 7399 case ADD_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, add, PETSC_FALSE, NULL, values, &offset, array)); 7407 } 7408 break; 7409 case ADD_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, add, PETSC_TRUE, NULL, values, &offset, array)); 7417 } 7418 break; 7419 default: 7420 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7421 } 7422 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7423 } 7424 /* Cleanup points */ 7425 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7426 /* Cleanup array */ 7427 PetscCall(VecRestoreArray(v, &array)); 7428 PetscFunctionReturn(PETSC_SUCCESS); 7429 } 7430 7431 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7432 { 7433 PetscMPIInt rank; 7434 PetscInt i, j; 7435 7436 PetscFunctionBegin; 7437 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7438 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7439 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7440 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7441 numCIndices = numCIndices ? numCIndices : numRIndices; 7442 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7443 for (i = 0; i < numRIndices; i++) { 7444 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7445 for (j = 0; j < numCIndices; j++) { 7446 #if defined(PETSC_USE_COMPLEX) 7447 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7448 #else 7449 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7450 #endif 7451 } 7452 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7453 } 7454 PetscFunctionReturn(PETSC_SUCCESS); 7455 } 7456 7457 /* 7458 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7459 7460 Input Parameters: 7461 + section - The section for this data layout 7462 . islocal - Is the section (and thus indices being requested) local or global? 7463 . point - The point contributing dofs with these indices 7464 . off - The global offset of this point 7465 . loff - The local offset of each field 7466 . setBC - The flag determining whether to include indices of boundary values 7467 . perm - A permutation of the dofs on this point, or NULL 7468 - indperm - A permutation of the entire indices array, or NULL 7469 7470 Output Parameter: 7471 . indices - Indices for dofs on this point 7472 7473 Level: developer 7474 7475 Note: The indices could be local or global, depending on the value of 'off'. 7476 */ 7477 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7478 { 7479 PetscInt dof; /* The number of unknowns on this point */ 7480 PetscInt cdof; /* The number of constraints on this point */ 7481 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7482 PetscInt cind = 0, k; 7483 7484 PetscFunctionBegin; 7485 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7486 PetscCall(PetscSectionGetDof(section, point, &dof)); 7487 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7488 if (!cdof || setBC) { 7489 for (k = 0; k < dof; ++k) { 7490 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7491 const PetscInt ind = indperm ? indperm[preind] : preind; 7492 7493 indices[ind] = off + k; 7494 } 7495 } else { 7496 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7497 for (k = 0; k < dof; ++k) { 7498 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7499 const PetscInt ind = indperm ? indperm[preind] : preind; 7500 7501 if ((cind < cdof) && (k == cdofs[cind])) { 7502 /* Insert check for returning constrained indices */ 7503 indices[ind] = -(off + k + 1); 7504 ++cind; 7505 } else { 7506 indices[ind] = off + k - (islocal ? 0 : cind); 7507 } 7508 } 7509 } 7510 *loff += dof; 7511 PetscFunctionReturn(PETSC_SUCCESS); 7512 } 7513 7514 /* 7515 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7516 7517 Input Parameters: 7518 + section - a section (global or local) 7519 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7520 . point - point within section 7521 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7522 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7523 . setBC - identify constrained (boundary condition) points via involution. 7524 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7525 . permsoff - offset 7526 - indperm - index permutation 7527 7528 Output Parameter: 7529 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7530 . indices - array to hold indices (as defined by section) of each dof associated with point 7531 7532 Notes: 7533 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7534 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7535 in the local vector. 7536 7537 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7538 significant). It is invalid to call with a global section and setBC=true. 7539 7540 Developer Note: 7541 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7542 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7543 offset could be obtained from the section instead of passing it explicitly as we do now. 7544 7545 Example: 7546 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7547 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7548 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7549 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. 7550 7551 Level: developer 7552 */ 7553 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[]) 7554 { 7555 PetscInt numFields, foff, f; 7556 7557 PetscFunctionBegin; 7558 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7559 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7560 for (f = 0, foff = 0; f < numFields; ++f) { 7561 PetscInt fdof, cfdof; 7562 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7563 PetscInt cind = 0, b; 7564 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7565 7566 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7567 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7568 if (!cfdof || setBC) { 7569 for (b = 0; b < fdof; ++b) { 7570 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7571 const PetscInt ind = indperm ? indperm[preind] : preind; 7572 7573 indices[ind] = off + foff + b; 7574 } 7575 } else { 7576 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7577 for (b = 0; b < fdof; ++b) { 7578 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7579 const PetscInt ind = indperm ? indperm[preind] : preind; 7580 7581 if ((cind < cfdof) && (b == fcdofs[cind])) { 7582 indices[ind] = -(off + foff + b + 1); 7583 ++cind; 7584 } else { 7585 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7586 } 7587 } 7588 } 7589 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7590 foffs[f] += fdof; 7591 } 7592 PetscFunctionReturn(PETSC_SUCCESS); 7593 } 7594 7595 /* 7596 This version believes the globalSection offsets for each field, rather than just the point offset 7597 7598 . foffs - The offset into 'indices' for each field, since it is segregated by field 7599 7600 Notes: 7601 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7602 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7603 */ 7604 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7605 { 7606 PetscInt numFields, foff, f; 7607 7608 PetscFunctionBegin; 7609 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7610 for (f = 0; f < numFields; ++f) { 7611 PetscInt fdof, cfdof; 7612 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7613 PetscInt cind = 0, b; 7614 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7615 7616 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7617 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7618 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7619 if (!cfdof) { 7620 for (b = 0; b < fdof; ++b) { 7621 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7622 const PetscInt ind = indperm ? indperm[preind] : preind; 7623 7624 indices[ind] = foff + b; 7625 } 7626 } else { 7627 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7628 for (b = 0; b < fdof; ++b) { 7629 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7630 const PetscInt ind = indperm ? indperm[preind] : preind; 7631 7632 if ((cind < cfdof) && (b == fcdofs[cind])) { 7633 indices[ind] = -(foff + b + 1); 7634 ++cind; 7635 } else { 7636 indices[ind] = foff + b - cind; 7637 } 7638 } 7639 } 7640 foffs[f] += fdof; 7641 } 7642 PetscFunctionReturn(PETSC_SUCCESS); 7643 } 7644 7645 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7646 { 7647 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7648 7649 PetscFunctionBegin; 7650 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7651 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7652 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7653 for (PetscInt p = 0; p < nPoints; p++) { 7654 PetscInt b = pnts[2 * p]; 7655 PetscInt bSecDof = 0, bOff; 7656 PetscInt cSecDof = 0; 7657 PetscSection indices_section; 7658 7659 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7660 if (!bSecDof) continue; 7661 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7662 indices_section = cSecDof > 0 ? cSec : section; 7663 if (numFields) { 7664 PetscInt fStart[32], fEnd[32]; 7665 7666 fStart[0] = 0; 7667 fEnd[0] = 0; 7668 for (PetscInt f = 0; f < numFields; f++) { 7669 PetscInt fDof = 0; 7670 7671 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7672 fStart[f + 1] = fStart[f] + fDof; 7673 fEnd[f + 1] = fStart[f + 1]; 7674 } 7675 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7676 // only apply permutations on one side 7677 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7678 for (PetscInt f = 0; f < numFields; f++) { 7679 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7680 } 7681 } else { 7682 PetscInt bEnd = 0; 7683 7684 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7685 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7686 7687 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7688 } 7689 } 7690 PetscFunctionReturn(PETSC_SUCCESS); 7691 } 7692 7693 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[]) 7694 { 7695 Mat cMat; 7696 PetscSection aSec, cSec; 7697 IS aIS; 7698 PetscInt aStart = -1, aEnd = -1; 7699 PetscInt sStart = -1, sEnd = -1; 7700 PetscInt cStart = -1, cEnd = -1; 7701 const PetscInt *anchors; 7702 PetscInt numFields, p; 7703 PetscInt newNumPoints = 0, newNumIndices = 0; 7704 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7705 PetscInt oldOffsets[32]; 7706 PetscInt newOffsets[32]; 7707 PetscInt oldOffsetsCopy[32]; 7708 PetscInt newOffsetsCopy[32]; 7709 PetscScalar *modMat = NULL; 7710 PetscBool anyConstrained = PETSC_FALSE; 7711 7712 PetscFunctionBegin; 7713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7714 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7715 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7716 7717 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7718 /* if there are point-to-point constraints */ 7719 if (aSec) { 7720 PetscCall(PetscArrayzero(newOffsets, 32)); 7721 PetscCall(PetscArrayzero(oldOffsets, 32)); 7722 PetscCall(ISGetIndices(aIS, &anchors)); 7723 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7724 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7725 /* figure out how many points are going to be in the new element matrix 7726 * (we allow double counting, because it's all just going to be summed 7727 * into the global matrix anyway) */ 7728 for (p = 0; p < 2 * numPoints; p += 2) { 7729 PetscInt b = points[p]; 7730 PetscInt bDof = 0, bSecDof = 0; 7731 7732 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7733 if (!bSecDof) continue; 7734 7735 for (PetscInt f = 0; f < numFields; f++) { 7736 PetscInt fDof = 0; 7737 7738 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7739 oldOffsets[f + 1] += fDof; 7740 } 7741 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7742 if (bDof) { 7743 /* this point is constrained */ 7744 /* it is going to be replaced by its anchors */ 7745 PetscInt bOff, q; 7746 7747 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7748 for (q = 0; q < bDof; q++) { 7749 PetscInt a = anchors[bOff + q]; 7750 PetscInt aDof = 0; 7751 7752 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7753 if (aDof) { 7754 anyConstrained = PETSC_TRUE; 7755 newNumPoints += 1; 7756 } 7757 newNumIndices += aDof; 7758 for (PetscInt f = 0; f < numFields; ++f) { 7759 PetscInt fDof = 0; 7760 7761 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7762 newOffsets[f + 1] += fDof; 7763 } 7764 } 7765 } else { 7766 /* this point is not constrained */ 7767 newNumPoints++; 7768 newNumIndices += bSecDof; 7769 for (PetscInt f = 0; f < numFields; ++f) { 7770 PetscInt fDof; 7771 7772 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7773 newOffsets[f + 1] += fDof; 7774 } 7775 } 7776 } 7777 } 7778 if (!anyConstrained) { 7779 if (outNumPoints) *outNumPoints = 0; 7780 if (outNumIndices) *outNumIndices = 0; 7781 if (outPoints) *outPoints = NULL; 7782 if (outMat) *outMat = NULL; 7783 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7784 PetscFunctionReturn(PETSC_SUCCESS); 7785 } 7786 7787 if (outNumPoints) *outNumPoints = newNumPoints; 7788 if (outNumIndices) *outNumIndices = newNumIndices; 7789 7790 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7791 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7792 7793 if (!outPoints && !outMat) { 7794 if (offsets) { 7795 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7796 } 7797 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7798 PetscFunctionReturn(PETSC_SUCCESS); 7799 } 7800 7801 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7802 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7803 7804 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7805 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7806 7807 /* output arrays */ 7808 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7809 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7810 7811 // get the new Points 7812 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7813 PetscInt b = points[2 * p]; 7814 PetscInt bDof = 0, bSecDof = 0, bOff; 7815 7816 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7817 if (!bSecDof) continue; 7818 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7819 if (bDof) { 7820 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7821 for (PetscInt q = 0; q < bDof; q++) { 7822 PetscInt a = anchors[bOff + q], aDof = 0; 7823 7824 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7825 if (aDof) { 7826 newPoints[2 * newP] = a; 7827 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7828 newP++; 7829 } 7830 } 7831 } else { 7832 newPoints[2 * newP] = b; 7833 newPoints[2 * newP + 1] = points[2 * p + 1]; 7834 newP++; 7835 } 7836 } 7837 7838 if (outMat) { 7839 PetscScalar *tmpMat; 7840 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7841 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7842 7843 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7844 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7845 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7846 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7847 7848 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7849 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7850 7851 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7852 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7853 7854 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7855 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7856 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7857 // for each field, insert the anchor modification into modMat 7858 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7859 PetscInt fStart = oldOffsets[f]; 7860 PetscInt fNewStart = newOffsets[f]; 7861 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7862 PetscInt b = points[2 * p]; 7863 PetscInt bDof = 0, bSecDof = 0, bOff; 7864 7865 if (b >= sStart && b < sEnd) { 7866 if (numFields) { 7867 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7868 } else { 7869 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7870 } 7871 } 7872 if (!bSecDof) continue; 7873 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7874 if (bDof) { 7875 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7876 for (PetscInt q = 0; q < bDof; q++, newP++) { 7877 PetscInt a = anchors[bOff + q], aDof = 0; 7878 7879 if (a >= sStart && a < sEnd) { 7880 if (numFields) { 7881 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7882 } else { 7883 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7884 } 7885 } 7886 if (aDof) { 7887 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7888 for (PetscInt d = 0; d < bSecDof; d++) { 7889 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7890 } 7891 } 7892 oNew += aDof; 7893 } 7894 } else { 7895 // Insert the identity matrix in this block 7896 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7897 oNew += bSecDof; 7898 newP++; 7899 } 7900 o += bSecDof; 7901 } 7902 } 7903 7904 *outMat = modMat; 7905 7906 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7907 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7908 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7909 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7910 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7911 } 7912 PetscCall(ISRestoreIndices(aIS, &anchors)); 7913 7914 /* output */ 7915 if (outPoints) { 7916 *outPoints = newPoints; 7917 } else { 7918 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7919 } 7920 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7921 PetscFunctionReturn(PETSC_SUCCESS); 7922 } 7923 7924 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) 7925 { 7926 PetscScalar *modMat = NULL; 7927 PetscInt newNumIndices = -1; 7928 7929 PetscFunctionBegin; 7930 /* 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. 7931 modMat is that matrix C */ 7932 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7933 if (outNumIndices) *outNumIndices = newNumIndices; 7934 if (modMat) { 7935 const PetscScalar *newValues = values; 7936 7937 if (multiplyRight) { 7938 PetscScalar *newNewValues = NULL; 7939 PetscBLASInt M, N, K; 7940 PetscScalar a = 1.0, b = 0.0; 7941 7942 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); 7943 7944 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7945 PetscCall(PetscBLASIntCast(numRows, &N)); 7946 PetscCall(PetscBLASIntCast(numIndices, &K)); 7947 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7948 // row-major to column-major conversion, right multiplication becomes left multiplication 7949 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7950 numCols = newNumIndices; 7951 newValues = newNewValues; 7952 } 7953 7954 if (multiplyLeft) { 7955 PetscScalar *newNewValues = NULL; 7956 PetscBLASInt M, N, K; 7957 PetscScalar a = 1.0, b = 0.0; 7958 7959 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); 7960 7961 PetscCall(PetscBLASIntCast(numCols, &M)); 7962 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7963 PetscCall(PetscBLASIntCast(numIndices, &K)); 7964 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7965 // row-major to column-major conversion, left multiplication becomes right multiplication 7966 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7967 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7968 newValues = newNewValues; 7969 } 7970 *outValues = (PetscScalar *)newValues; 7971 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7972 } 7973 PetscFunctionReturn(PETSC_SUCCESS); 7974 } 7975 7976 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) 7977 { 7978 PetscFunctionBegin; 7979 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7980 PetscFunctionReturn(PETSC_SUCCESS); 7981 } 7982 7983 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7984 { 7985 /* Closure ordering */ 7986 PetscSection clSection; 7987 IS clPoints; 7988 const PetscInt *clp; 7989 PetscInt *points; 7990 PetscInt Ncl, Ni = 0; 7991 7992 PetscFunctionBeginHot; 7993 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7994 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7995 PetscInt dof; 7996 7997 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7998 Ni += dof; 7999 } 8000 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8001 *closureSize = Ni; 8002 PetscFunctionReturn(PETSC_SUCCESS); 8003 } 8004 8005 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) 8006 { 8007 /* Closure ordering */ 8008 PetscSection clSection; 8009 IS clPoints; 8010 const PetscInt *clp; 8011 PetscInt *points; 8012 const PetscInt *clperm = NULL; 8013 /* Dof permutation and sign flips */ 8014 const PetscInt **perms[32] = {NULL}; 8015 const PetscScalar **flips[32] = {NULL}; 8016 PetscScalar *valCopy = NULL; 8017 /* Hanging node constraints */ 8018 PetscInt *pointsC = NULL; 8019 PetscScalar *valuesC = NULL; 8020 PetscInt NclC, NiC; 8021 8022 PetscInt *idx; 8023 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8024 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8025 PetscInt idxStart, idxEnd; 8026 PetscInt nRows, nCols; 8027 8028 PetscFunctionBeginHot; 8029 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8030 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8031 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8032 PetscAssertPointer(numRows, 6); 8033 PetscAssertPointer(numCols, 7); 8034 if (indices) PetscAssertPointer(indices, 8); 8035 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8036 if (values) PetscAssertPointer(values, 10); 8037 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8038 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8039 PetscCall(PetscArrayzero(offsets, 32)); 8040 /* 1) Get points in closure */ 8041 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8042 if (useClPerm) { 8043 PetscInt depth, clsize; 8044 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8045 for (clsize = 0, p = 0; p < Ncl; p++) { 8046 PetscInt dof; 8047 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8048 clsize += dof; 8049 } 8050 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8051 } 8052 /* 2) Get number of indices on these points and field offsets from section */ 8053 for (p = 0; p < Ncl * 2; p += 2) { 8054 PetscInt dof, fdof; 8055 8056 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8057 for (f = 0; f < Nf; ++f) { 8058 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8059 offsets[f + 1] += fdof; 8060 } 8061 Ni += dof; 8062 } 8063 if (*numRows == -1) *numRows = Ni; 8064 if (*numCols == -1) *numCols = Ni; 8065 nRows = *numRows; 8066 nCols = *numCols; 8067 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8068 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8069 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8070 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8071 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8072 for (f = 0; f < PetscMax(1, Nf); ++f) { 8073 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8074 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8075 /* may need to apply sign changes to the element matrix */ 8076 if (values && flips[f]) { 8077 PetscInt foffset = offsets[f]; 8078 8079 for (p = 0; p < Ncl; ++p) { 8080 PetscInt pnt = points[2 * p], fdof; 8081 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8082 8083 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8084 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8085 if (flip) { 8086 PetscInt i, j, k; 8087 8088 if (!valCopy) { 8089 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8090 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8091 *values = valCopy; 8092 } 8093 for (i = 0; i < fdof; ++i) { 8094 PetscScalar fval = flip[i]; 8095 8096 if (multiplyRight) { 8097 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8098 } 8099 if (multiplyLeft) { 8100 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8101 } 8102 } 8103 } 8104 foffset += fdof; 8105 } 8106 } 8107 } 8108 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8109 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8110 if (NclC) { 8111 if (multiplyRight) *numCols = NiC; 8112 if (multiplyLeft) *numRows = NiC; 8113 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8114 for (f = 0; f < PetscMax(1, Nf); ++f) { 8115 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8116 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8117 } 8118 for (f = 0; f < PetscMax(1, Nf); ++f) { 8119 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8120 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8121 } 8122 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8123 Ncl = NclC; 8124 Ni = NiC; 8125 points = pointsC; 8126 if (values) *values = valuesC; 8127 } 8128 /* 5) Calculate indices */ 8129 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8130 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8131 if (Nf) { 8132 PetscInt idxOff; 8133 PetscBool useFieldOffsets; 8134 8135 if (outOffsets) { 8136 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8137 } 8138 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8139 if (useFieldOffsets) { 8140 for (p = 0; p < Ncl; ++p) { 8141 const PetscInt pnt = points[p * 2]; 8142 8143 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8144 } 8145 } else { 8146 for (p = 0; p < Ncl; ++p) { 8147 const PetscInt pnt = points[p * 2]; 8148 8149 if (pnt < idxStart || pnt >= idxEnd) continue; 8150 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8151 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8152 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8153 * global section. */ 8154 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8155 } 8156 } 8157 } else { 8158 PetscInt off = 0, idxOff; 8159 8160 for (p = 0; p < Ncl; ++p) { 8161 const PetscInt pnt = points[p * 2]; 8162 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8163 8164 if (pnt < idxStart || pnt >= idxEnd) continue; 8165 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8166 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8167 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8168 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8169 } 8170 } 8171 /* 6) Cleanup */ 8172 for (f = 0; f < PetscMax(1, Nf); ++f) { 8173 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8174 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8175 } 8176 if (NclC) { 8177 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8178 } else { 8179 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8180 } 8181 8182 if (indices) *indices = idx; 8183 PetscFunctionReturn(PETSC_SUCCESS); 8184 } 8185 8186 /*@C 8187 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8188 8189 Not collective 8190 8191 Input Parameters: 8192 + dm - The `DM` 8193 . section - The `PetscSection` describing the points (a local section) 8194 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8195 . point - The point defining the closure 8196 - useClPerm - Use the closure point permutation if available 8197 8198 Output Parameters: 8199 + numIndices - The number of dof indices in the closure of point with the input sections 8200 . indices - The dof indices 8201 . outOffsets - Array to write the field offsets into, or `NULL` 8202 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8203 8204 Level: advanced 8205 8206 Notes: 8207 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8208 8209 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8210 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8211 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8212 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8213 indices (with the above semantics) are implied. 8214 8215 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8216 `PetscSection`, `DMGetGlobalSection()` 8217 @*/ 8218 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8219 { 8220 PetscInt numRows = -1, numCols = -1; 8221 8222 PetscFunctionBeginHot; 8223 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8224 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8225 *numIndices = numRows; 8226 PetscFunctionReturn(PETSC_SUCCESS); 8227 } 8228 8229 /*@C 8230 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8231 8232 Not collective 8233 8234 Input Parameters: 8235 + dm - The `DM` 8236 . section - The `PetscSection` describing the points (a local section) 8237 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8238 . point - The point defining the closure 8239 - useClPerm - Use the closure point permutation if available 8240 8241 Output Parameters: 8242 + numIndices - The number of dof indices in the closure of point with the input sections 8243 . indices - The dof indices 8244 . outOffsets - Array to write the field offsets into, or `NULL` 8245 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8246 8247 Level: advanced 8248 8249 Notes: 8250 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8251 8252 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8253 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8254 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8255 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8256 indices (with the above semantics) are implied. 8257 8258 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8259 @*/ 8260 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8261 { 8262 PetscFunctionBegin; 8263 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8264 PetscAssertPointer(indices, 7); 8265 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8266 PetscFunctionReturn(PETSC_SUCCESS); 8267 } 8268 8269 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8270 { 8271 DM_Plex *mesh = (DM_Plex *)dm->data; 8272 PetscInt *indices; 8273 PetscInt numIndices; 8274 const PetscScalar *valuesOrig = values; 8275 PetscErrorCode ierr; 8276 8277 PetscFunctionBegin; 8278 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8279 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8280 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8281 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8282 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8283 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8284 8285 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8286 8287 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8288 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8289 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8290 if (ierr) { 8291 PetscMPIInt rank; 8292 8293 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8294 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8295 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8296 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8297 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8298 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8299 } 8300 if (mesh->printFEM > 1) { 8301 PetscInt i; 8302 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8303 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8304 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8305 } 8306 8307 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8308 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8309 PetscFunctionReturn(PETSC_SUCCESS); 8310 } 8311 8312 /*@C 8313 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8314 8315 Not collective 8316 8317 Input Parameters: 8318 + dm - The `DM` 8319 . section - The section describing the layout in `v`, or `NULL` to use the default section 8320 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8321 . A - The matrix 8322 . point - The point in the `DM` 8323 . values - The array of values 8324 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8325 8326 Level: intermediate 8327 8328 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8329 @*/ 8330 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8331 { 8332 PetscFunctionBegin; 8333 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8334 PetscFunctionReturn(PETSC_SUCCESS); 8335 } 8336 8337 /*@C 8338 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8339 8340 Not collective 8341 8342 Input Parameters: 8343 + dmRow - The `DM` for the row fields 8344 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8345 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8346 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8347 . dmCol - The `DM` for the column fields 8348 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8349 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8350 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 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`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8359 @*/ 8360 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) 8361 { 8362 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8363 PetscInt *indicesRow, *indicesCol; 8364 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8365 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8366 8367 PetscErrorCode ierr; 8368 8369 PetscFunctionBegin; 8370 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8371 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8372 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8373 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8374 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8375 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8376 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8377 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8378 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8379 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8380 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8381 8382 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8383 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8384 valuesV1 = valuesV0; 8385 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8386 valuesV2 = valuesV1; 8387 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8388 8389 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8390 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8391 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8392 if (ierr) { 8393 PetscMPIInt rank; 8394 8395 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8396 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8397 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8398 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8399 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8400 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8401 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8402 } 8403 8404 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8405 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8406 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8407 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8408 PetscFunctionReturn(PETSC_SUCCESS); 8409 } 8410 8411 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8412 { 8413 DM_Plex *mesh = (DM_Plex *)dmf->data; 8414 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8415 PetscInt *cpoints = NULL; 8416 PetscInt *findices, *cindices; 8417 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8418 PetscInt foffsets[32], coffsets[32]; 8419 DMPolytopeType ct; 8420 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8421 PetscErrorCode ierr; 8422 8423 PetscFunctionBegin; 8424 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8425 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8426 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8427 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8428 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8429 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8430 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8431 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8432 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8433 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8434 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8435 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8436 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8437 PetscCall(PetscArrayzero(foffsets, 32)); 8438 PetscCall(PetscArrayzero(coffsets, 32)); 8439 /* Column indices */ 8440 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8441 maxFPoints = numCPoints; 8442 /* Compress out points not in the section */ 8443 /* TODO: Squeeze out points with 0 dof as well */ 8444 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8445 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8446 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8447 cpoints[q * 2] = cpoints[p]; 8448 cpoints[q * 2 + 1] = cpoints[p + 1]; 8449 ++q; 8450 } 8451 } 8452 numCPoints = q; 8453 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8454 PetscInt fdof; 8455 8456 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8457 if (!dof) continue; 8458 for (f = 0; f < numFields; ++f) { 8459 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8460 coffsets[f + 1] += fdof; 8461 } 8462 numCIndices += dof; 8463 } 8464 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8465 /* Row indices */ 8466 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8467 { 8468 DMPlexTransform tr; 8469 DMPolytopeType *rct; 8470 PetscInt *rsize, *rcone, *rornt, Nt; 8471 8472 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8473 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8474 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8475 numSubcells = rsize[Nt - 1]; 8476 PetscCall(DMPlexTransformDestroy(&tr)); 8477 } 8478 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8479 for (r = 0, q = 0; r < numSubcells; ++r) { 8480 /* TODO Map from coarse to fine cells */ 8481 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8482 /* Compress out points not in the section */ 8483 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8484 for (p = 0; p < numFPoints * 2; p += 2) { 8485 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8486 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8487 if (!dof) continue; 8488 for (s = 0; s < q; ++s) 8489 if (fpoints[p] == ftotpoints[s * 2]) break; 8490 if (s < q) continue; 8491 ftotpoints[q * 2] = fpoints[p]; 8492 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8493 ++q; 8494 } 8495 } 8496 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8497 } 8498 numFPoints = q; 8499 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8500 PetscInt fdof; 8501 8502 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8503 if (!dof) continue; 8504 for (f = 0; f < numFields; ++f) { 8505 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8506 foffsets[f + 1] += fdof; 8507 } 8508 numFIndices += dof; 8509 } 8510 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8511 8512 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8513 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8514 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8515 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8516 if (numFields) { 8517 const PetscInt **permsF[32] = {NULL}; 8518 const PetscInt **permsC[32] = {NULL}; 8519 8520 for (f = 0; f < numFields; f++) { 8521 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8522 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8523 } 8524 for (p = 0; p < numFPoints; p++) { 8525 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8526 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8527 } 8528 for (p = 0; p < numCPoints; p++) { 8529 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8530 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8531 } 8532 for (f = 0; f < numFields; f++) { 8533 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8534 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8535 } 8536 } else { 8537 const PetscInt **permsF = NULL; 8538 const PetscInt **permsC = NULL; 8539 8540 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8541 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8542 for (p = 0, off = 0; p < numFPoints; p++) { 8543 const PetscInt *perm = permsF ? permsF[p] : NULL; 8544 8545 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8546 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8547 } 8548 for (p = 0, off = 0; p < numCPoints; p++) { 8549 const PetscInt *perm = permsC ? permsC[p] : NULL; 8550 8551 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8552 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8553 } 8554 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8555 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8556 } 8557 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8558 /* TODO: flips */ 8559 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8560 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8561 if (ierr) { 8562 PetscMPIInt rank; 8563 8564 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8565 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8566 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8567 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8568 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8569 } 8570 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8571 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8572 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8573 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8574 PetscFunctionReturn(PETSC_SUCCESS); 8575 } 8576 8577 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8578 { 8579 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8580 PetscInt *cpoints = NULL; 8581 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8582 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8583 DMPolytopeType ct; 8584 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8585 8586 PetscFunctionBegin; 8587 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8588 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8589 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8590 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8591 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8592 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8593 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8594 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8595 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8596 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8597 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8598 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8599 /* Column indices */ 8600 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8601 maxFPoints = numCPoints; 8602 /* Compress out points not in the section */ 8603 /* TODO: Squeeze out points with 0 dof as well */ 8604 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8605 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8606 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8607 cpoints[q * 2] = cpoints[p]; 8608 cpoints[q * 2 + 1] = cpoints[p + 1]; 8609 ++q; 8610 } 8611 } 8612 numCPoints = q; 8613 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8614 PetscInt fdof; 8615 8616 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8617 if (!dof) continue; 8618 for (f = 0; f < numFields; ++f) { 8619 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8620 coffsets[f + 1] += fdof; 8621 } 8622 numCIndices += dof; 8623 } 8624 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8625 /* Row indices */ 8626 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8627 { 8628 DMPlexTransform tr; 8629 DMPolytopeType *rct; 8630 PetscInt *rsize, *rcone, *rornt, Nt; 8631 8632 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8633 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8634 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8635 numSubcells = rsize[Nt - 1]; 8636 PetscCall(DMPlexTransformDestroy(&tr)); 8637 } 8638 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8639 for (r = 0, q = 0; r < numSubcells; ++r) { 8640 /* TODO Map from coarse to fine cells */ 8641 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8642 /* Compress out points not in the section */ 8643 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8644 for (p = 0; p < numFPoints * 2; p += 2) { 8645 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8646 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8647 if (!dof) continue; 8648 for (s = 0; s < q; ++s) 8649 if (fpoints[p] == ftotpoints[s * 2]) break; 8650 if (s < q) continue; 8651 ftotpoints[q * 2] = fpoints[p]; 8652 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8653 ++q; 8654 } 8655 } 8656 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8657 } 8658 numFPoints = q; 8659 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8660 PetscInt fdof; 8661 8662 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8663 if (!dof) continue; 8664 for (f = 0; f < numFields; ++f) { 8665 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8666 foffsets[f + 1] += fdof; 8667 } 8668 numFIndices += dof; 8669 } 8670 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8671 8672 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8673 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8674 if (numFields) { 8675 const PetscInt **permsF[32] = {NULL}; 8676 const PetscInt **permsC[32] = {NULL}; 8677 8678 for (f = 0; f < numFields; f++) { 8679 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8680 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8681 } 8682 for (p = 0; p < numFPoints; p++) { 8683 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8684 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8685 } 8686 for (p = 0; p < numCPoints; p++) { 8687 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8688 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8689 } 8690 for (f = 0; f < numFields; f++) { 8691 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8692 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8693 } 8694 } else { 8695 const PetscInt **permsF = NULL; 8696 const PetscInt **permsC = NULL; 8697 8698 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8699 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8700 for (p = 0, off = 0; p < numFPoints; p++) { 8701 const PetscInt *perm = permsF ? permsF[p] : NULL; 8702 8703 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8704 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8705 } 8706 for (p = 0, off = 0; p < numCPoints; p++) { 8707 const PetscInt *perm = permsC ? permsC[p] : NULL; 8708 8709 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8710 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8711 } 8712 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8713 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8714 } 8715 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8716 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8717 PetscFunctionReturn(PETSC_SUCCESS); 8718 } 8719 8720 /*@ 8721 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8722 8723 Input Parameter: 8724 . dm - The `DMPLEX` object 8725 8726 Output Parameter: 8727 . cellHeight - The height of a cell 8728 8729 Level: developer 8730 8731 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8732 @*/ 8733 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8734 { 8735 DM_Plex *mesh = (DM_Plex *)dm->data; 8736 8737 PetscFunctionBegin; 8738 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8739 PetscAssertPointer(cellHeight, 2); 8740 *cellHeight = mesh->vtkCellHeight; 8741 PetscFunctionReturn(PETSC_SUCCESS); 8742 } 8743 8744 /*@ 8745 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8746 8747 Input Parameters: 8748 + dm - The `DMPLEX` object 8749 - cellHeight - The height of a cell 8750 8751 Level: developer 8752 8753 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8754 @*/ 8755 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8756 { 8757 DM_Plex *mesh = (DM_Plex *)dm->data; 8758 8759 PetscFunctionBegin; 8760 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8761 mesh->vtkCellHeight = cellHeight; 8762 PetscFunctionReturn(PETSC_SUCCESS); 8763 } 8764 8765 /*@ 8766 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8767 8768 Input Parameters: 8769 + dm - The `DMPLEX` object 8770 - ct - The `DMPolytopeType` of the cell 8771 8772 Output Parameters: 8773 + start - The first cell of this type, or `NULL` 8774 - end - The upper bound on this celltype, or `NULL` 8775 8776 Level: advanced 8777 8778 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8779 @*/ 8780 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8781 { 8782 DM_Plex *mesh = (DM_Plex *)dm->data; 8783 DMLabel label; 8784 PetscInt pStart, pEnd; 8785 8786 PetscFunctionBegin; 8787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8788 if (start) { 8789 PetscAssertPointer(start, 3); 8790 *start = 0; 8791 } 8792 if (end) { 8793 PetscAssertPointer(end, 4); 8794 *end = 0; 8795 } 8796 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8797 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8798 if (mesh->tr) { 8799 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8800 } else { 8801 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8802 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8803 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8804 } 8805 PetscFunctionReturn(PETSC_SUCCESS); 8806 } 8807 8808 /*@ 8809 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8810 8811 Input Parameters: 8812 + dm - The `DMPLEX` object 8813 - depth - The depth for the given point stratum 8814 8815 Output Parameter: 8816 . gsize - The global number of points in the stratum 8817 8818 Level: advanced 8819 8820 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8821 @*/ 8822 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8823 { 8824 PetscSF sf; 8825 const PetscInt *leaves; 8826 PetscInt Nl, loc, start, end, lsize = 0; 8827 8828 PetscFunctionBegin; 8829 PetscCall(DMGetPointSF(dm, &sf)); 8830 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8831 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8832 for (PetscInt p = start; p < end; ++p) { 8833 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8834 if (loc < 0) ++lsize; 8835 } 8836 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8837 PetscFunctionReturn(PETSC_SUCCESS); 8838 } 8839 8840 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8841 { 8842 PetscSection section, globalSection; 8843 PetscInt *numbers, p; 8844 8845 PetscFunctionBegin; 8846 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8847 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8848 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8849 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8850 PetscCall(PetscSectionSetUp(section)); 8851 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8852 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8853 for (p = pStart; p < pEnd; ++p) { 8854 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8855 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8856 else numbers[p - pStart] += shift; 8857 } 8858 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8859 if (globalSize) { 8860 PetscLayout layout; 8861 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8862 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8863 PetscCall(PetscLayoutDestroy(&layout)); 8864 } 8865 PetscCall(PetscSectionDestroy(§ion)); 8866 PetscCall(PetscSectionDestroy(&globalSection)); 8867 PetscFunctionReturn(PETSC_SUCCESS); 8868 } 8869 8870 /*@ 8871 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8872 8873 Input Parameters: 8874 + dm - The `DMPLEX` object 8875 - includeAll - Whether to include all cells, or just the simplex and box cells 8876 8877 Output Parameter: 8878 . globalCellNumbers - Global cell numbers for all cells on this process 8879 8880 Level: developer 8881 8882 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8883 @*/ 8884 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8885 { 8886 PetscInt cellHeight, cStart, cEnd; 8887 8888 PetscFunctionBegin; 8889 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8890 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8891 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8892 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8893 PetscFunctionReturn(PETSC_SUCCESS); 8894 } 8895 8896 /*@ 8897 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8898 8899 Input Parameter: 8900 . dm - The `DMPLEX` object 8901 8902 Output Parameter: 8903 . globalCellNumbers - Global cell numbers for all cells on this process 8904 8905 Level: developer 8906 8907 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8908 @*/ 8909 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8910 { 8911 DM_Plex *mesh = (DM_Plex *)dm->data; 8912 8913 PetscFunctionBegin; 8914 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8915 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8916 *globalCellNumbers = mesh->globalCellNumbers; 8917 PetscFunctionReturn(PETSC_SUCCESS); 8918 } 8919 8920 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8921 { 8922 PetscInt vStart, vEnd; 8923 8924 PetscFunctionBegin; 8925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8926 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8927 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8928 PetscFunctionReturn(PETSC_SUCCESS); 8929 } 8930 8931 /*@ 8932 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8933 8934 Input Parameter: 8935 . dm - The `DMPLEX` object 8936 8937 Output Parameter: 8938 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8939 8940 Level: developer 8941 8942 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8943 @*/ 8944 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8945 { 8946 DM_Plex *mesh = (DM_Plex *)dm->data; 8947 8948 PetscFunctionBegin; 8949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8950 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8951 *globalVertexNumbers = mesh->globalVertexNumbers; 8952 PetscFunctionReturn(PETSC_SUCCESS); 8953 } 8954 8955 /*@ 8956 DMPlexCreatePointNumbering - Create a global numbering for all points. 8957 8958 Collective 8959 8960 Input Parameter: 8961 . dm - The `DMPLEX` object 8962 8963 Output Parameter: 8964 . globalPointNumbers - Global numbers for all points on this process 8965 8966 Level: developer 8967 8968 Notes: 8969 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8970 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8971 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8972 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8973 8974 The partitioned mesh is 8975 ``` 8976 (2)--0--(3)--1--(4) (1)--0--(2) 8977 ``` 8978 and its global numbering is 8979 ``` 8980 (3)--0--(4)--1--(5)--2--(6) 8981 ``` 8982 Then the global numbering is provided as 8983 ``` 8984 [0] Number of indices in set 5 8985 [0] 0 0 8986 [0] 1 1 8987 [0] 2 3 8988 [0] 3 4 8989 [0] 4 -6 8990 [1] Number of indices in set 3 8991 [1] 0 2 8992 [1] 1 5 8993 [1] 2 6 8994 ``` 8995 8996 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8997 @*/ 8998 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8999 { 9000 IS nums[4]; 9001 PetscInt depths[4], gdepths[4], starts[4]; 9002 PetscInt depth, d, shift = 0; 9003 PetscBool empty = PETSC_FALSE; 9004 PetscMPIInt idepth; 9005 9006 PetscFunctionBegin; 9007 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9008 PetscCall(DMPlexGetDepth(dm, &depth)); 9009 // For unstratified meshes use dim instead of depth 9010 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9011 // If any stratum is empty, we must mark all empty 9012 for (d = 0; d <= depth; ++d) { 9013 PetscInt end; 9014 9015 depths[d] = depth - d; 9016 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9017 if (!(starts[d] - end)) empty = PETSC_TRUE; 9018 } 9019 if (empty) 9020 for (d = 0; d <= depth; ++d) { 9021 depths[d] = -1; 9022 starts[d] = -1; 9023 } 9024 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9025 PetscCall(PetscMPIIntCast(depth + 1, &idepth)); 9026 PetscCallMPI(MPIU_Allreduce(depths, gdepths, idepth, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9027 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]); 9028 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9029 for (d = 0; d <= depth; ++d) { 9030 PetscInt pStart, pEnd, gsize; 9031 9032 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9033 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9034 shift += gsize; 9035 } 9036 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9037 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9038 PetscFunctionReturn(PETSC_SUCCESS); 9039 } 9040 9041 /*@ 9042 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9043 9044 Collective 9045 9046 Input Parameter: 9047 . dm - The `DMPLEX` object 9048 9049 Output Parameter: 9050 . globalEdgeNumbers - Global numbers for all edges on this process 9051 9052 Level: developer 9053 9054 Notes: 9055 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). 9056 9057 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9058 @*/ 9059 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9060 { 9061 PetscSF sf; 9062 PetscInt eStart, eEnd; 9063 9064 PetscFunctionBegin; 9065 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9066 PetscCall(DMGetPointSF(dm, &sf)); 9067 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9068 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9069 PetscFunctionReturn(PETSC_SUCCESS); 9070 } 9071 9072 /*@ 9073 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9074 9075 Input Parameter: 9076 . dm - The `DMPLEX` object 9077 9078 Output Parameter: 9079 . ranks - The rank field 9080 9081 Options Database Key: 9082 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9083 9084 Level: intermediate 9085 9086 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9087 @*/ 9088 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9089 { 9090 DM rdm; 9091 PetscFE fe; 9092 PetscScalar *r; 9093 PetscMPIInt rank; 9094 DMPolytopeType ct; 9095 PetscInt dim, cStart, cEnd, c; 9096 PetscBool simplex; 9097 9098 PetscFunctionBeginUser; 9099 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9100 PetscAssertPointer(ranks, 2); 9101 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9102 PetscCall(DMClone(dm, &rdm)); 9103 PetscCall(DMGetDimension(rdm, &dim)); 9104 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9105 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9106 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9107 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9108 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9109 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9110 PetscCall(PetscFEDestroy(&fe)); 9111 PetscCall(DMCreateDS(rdm)); 9112 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9113 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9114 PetscCall(VecGetArray(*ranks, &r)); 9115 for (c = cStart; c < cEnd; ++c) { 9116 PetscScalar *lr; 9117 9118 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9119 if (lr) *lr = rank; 9120 } 9121 PetscCall(VecRestoreArray(*ranks, &r)); 9122 PetscCall(DMDestroy(&rdm)); 9123 PetscFunctionReturn(PETSC_SUCCESS); 9124 } 9125 9126 /*@ 9127 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9128 9129 Input Parameters: 9130 + dm - The `DMPLEX` 9131 - label - The `DMLabel` 9132 9133 Output Parameter: 9134 . val - The label value field 9135 9136 Options Database Key: 9137 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9138 9139 Level: intermediate 9140 9141 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9142 @*/ 9143 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9144 { 9145 DM rdm, plex; 9146 Vec lval; 9147 PetscSection section; 9148 PetscFE fe; 9149 PetscScalar *v; 9150 PetscInt dim, pStart, pEnd, p, cStart; 9151 DMPolytopeType ct; 9152 char name[PETSC_MAX_PATH_LEN]; 9153 const char *lname, *prefix; 9154 9155 PetscFunctionBeginUser; 9156 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9157 PetscAssertPointer(label, 2); 9158 PetscAssertPointer(val, 3); 9159 PetscCall(DMClone(dm, &rdm)); 9160 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9161 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9162 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9163 PetscCall(DMDestroy(&plex)); 9164 PetscCall(DMGetDimension(rdm, &dim)); 9165 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9166 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9167 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9168 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9169 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9170 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9171 PetscCall(PetscFEDestroy(&fe)); 9172 PetscCall(DMCreateDS(rdm)); 9173 PetscCall(DMCreateGlobalVector(rdm, val)); 9174 PetscCall(DMCreateLocalVector(rdm, &lval)); 9175 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9176 PetscCall(DMGetLocalSection(rdm, §ion)); 9177 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9178 PetscCall(VecGetArray(lval, &v)); 9179 for (p = pStart; p < pEnd; ++p) { 9180 PetscInt cval, dof, off; 9181 9182 PetscCall(PetscSectionGetDof(section, p, &dof)); 9183 if (!dof) continue; 9184 PetscCall(DMLabelGetValue(label, p, &cval)); 9185 PetscCall(PetscSectionGetOffset(section, p, &off)); 9186 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9187 } 9188 PetscCall(VecRestoreArray(lval, &v)); 9189 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9190 PetscCall(VecDestroy(&lval)); 9191 PetscCall(DMDestroy(&rdm)); 9192 PetscFunctionReturn(PETSC_SUCCESS); 9193 } 9194 9195 /*@ 9196 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9197 9198 Input Parameter: 9199 . dm - The `DMPLEX` object 9200 9201 Level: developer 9202 9203 Notes: 9204 This is a useful diagnostic when creating meshes programmatically. 9205 9206 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9207 9208 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9209 @*/ 9210 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9211 { 9212 PetscSection coneSection, supportSection; 9213 const PetscInt *cone, *support; 9214 PetscInt coneSize, c, supportSize, s; 9215 PetscInt pStart, pEnd, p, pp, csize, ssize; 9216 PetscBool storagecheck = PETSC_TRUE; 9217 9218 PetscFunctionBegin; 9219 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9220 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9221 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9222 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9223 /* Check that point p is found in the support of its cone points, and vice versa */ 9224 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9225 for (p = pStart; p < pEnd; ++p) { 9226 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9227 PetscCall(DMPlexGetCone(dm, p, &cone)); 9228 for (c = 0; c < coneSize; ++c) { 9229 PetscBool dup = PETSC_FALSE; 9230 PetscInt d; 9231 for (d = c - 1; d >= 0; --d) { 9232 if (cone[c] == cone[d]) { 9233 dup = PETSC_TRUE; 9234 break; 9235 } 9236 } 9237 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9238 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9239 for (s = 0; s < supportSize; ++s) { 9240 if (support[s] == p) break; 9241 } 9242 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9243 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9244 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9245 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9246 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9247 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9248 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9249 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]); 9250 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9251 } 9252 } 9253 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9254 if (p != pp) { 9255 storagecheck = PETSC_FALSE; 9256 continue; 9257 } 9258 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9259 PetscCall(DMPlexGetSupport(dm, p, &support)); 9260 for (s = 0; s < supportSize; ++s) { 9261 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9262 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9263 for (c = 0; c < coneSize; ++c) { 9264 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9265 if (cone[c] != pp) { 9266 c = 0; 9267 break; 9268 } 9269 if (cone[c] == p) break; 9270 } 9271 if (c >= coneSize) { 9272 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9273 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9274 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9275 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9276 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9277 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9278 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9279 } 9280 } 9281 } 9282 if (storagecheck) { 9283 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9284 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9285 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9286 } 9287 PetscFunctionReturn(PETSC_SUCCESS); 9288 } 9289 9290 /* 9291 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. 9292 */ 9293 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9294 { 9295 DMPolytopeType cct; 9296 PetscInt ptpoints[4]; 9297 const PetscInt *cone, *ccone, *ptcone; 9298 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9299 9300 PetscFunctionBegin; 9301 *unsplit = 0; 9302 switch (ct) { 9303 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9304 ptpoints[npt++] = c; 9305 break; 9306 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9307 PetscCall(DMPlexGetCone(dm, c, &cone)); 9308 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9309 for (cp = 0; cp < coneSize; ++cp) { 9310 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9311 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9312 } 9313 break; 9314 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9315 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9316 PetscCall(DMPlexGetCone(dm, c, &cone)); 9317 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9318 for (cp = 0; cp < coneSize; ++cp) { 9319 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9320 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9321 for (ccp = 0; ccp < cconeSize; ++ccp) { 9322 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9323 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9324 PetscInt p; 9325 for (p = 0; p < npt; ++p) 9326 if (ptpoints[p] == ccone[ccp]) break; 9327 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9328 } 9329 } 9330 } 9331 break; 9332 default: 9333 break; 9334 } 9335 for (pt = 0; pt < npt; ++pt) { 9336 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9337 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9338 } 9339 PetscFunctionReturn(PETSC_SUCCESS); 9340 } 9341 9342 /*@ 9343 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9344 9345 Input Parameters: 9346 + dm - The `DMPLEX` object 9347 - cellHeight - Normally 0 9348 9349 Level: developer 9350 9351 Notes: 9352 This is a useful diagnostic when creating meshes programmatically. 9353 Currently applicable only to homogeneous simplex or tensor meshes. 9354 9355 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9356 9357 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9358 @*/ 9359 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9360 { 9361 DMPlexInterpolatedFlag interp; 9362 DMPolytopeType ct; 9363 PetscInt vStart, vEnd, cStart, cEnd, c; 9364 9365 PetscFunctionBegin; 9366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9367 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9368 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9369 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9370 for (c = cStart; c < cEnd; ++c) { 9371 PetscInt *closure = NULL; 9372 PetscInt coneSize, closureSize, cl, Nv = 0; 9373 9374 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9375 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9376 if (interp == DMPLEX_INTERPOLATED_FULL) { 9377 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9378 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)); 9379 } 9380 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9381 for (cl = 0; cl < closureSize * 2; cl += 2) { 9382 const PetscInt p = closure[cl]; 9383 if ((p >= vStart) && (p < vEnd)) ++Nv; 9384 } 9385 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9386 /* Special Case: Tensor faces with identified vertices */ 9387 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9388 PetscInt unsplit; 9389 9390 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9391 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9392 } 9393 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)); 9394 } 9395 PetscFunctionReturn(PETSC_SUCCESS); 9396 } 9397 9398 /*@ 9399 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9400 9401 Collective 9402 9403 Input Parameters: 9404 + dm - The `DMPLEX` object 9405 - cellHeight - Normally 0 9406 9407 Level: developer 9408 9409 Notes: 9410 This is a useful diagnostic when creating meshes programmatically. 9411 This routine is only relevant for meshes that are fully interpolated across all ranks. 9412 It will error out if a partially interpolated mesh is given on some rank. 9413 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9414 9415 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9416 9417 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9418 @*/ 9419 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9420 { 9421 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9422 DMPlexInterpolatedFlag interpEnum; 9423 9424 PetscFunctionBegin; 9425 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9426 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9427 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9428 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9429 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9430 PetscFunctionReturn(PETSC_SUCCESS); 9431 } 9432 9433 PetscCall(DMGetDimension(dm, &dim)); 9434 PetscCall(DMPlexGetDepth(dm, &depth)); 9435 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9436 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9437 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9438 for (c = cStart; c < cEnd; ++c) { 9439 const PetscInt *cone, *ornt, *faceSizes, *faces; 9440 const DMPolytopeType *faceTypes; 9441 DMPolytopeType ct; 9442 PetscInt numFaces, coneSize, f; 9443 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9444 9445 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9446 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9447 if (unsplit) continue; 9448 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9449 PetscCall(DMPlexGetCone(dm, c, &cone)); 9450 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9451 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9452 for (cl = 0; cl < closureSize * 2; cl += 2) { 9453 const PetscInt p = closure[cl]; 9454 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9455 } 9456 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9457 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); 9458 for (f = 0; f < numFaces; ++f) { 9459 DMPolytopeType fct; 9460 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9461 9462 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9463 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9464 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9465 const PetscInt p = fclosure[cl]; 9466 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9467 } 9468 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]); 9469 for (v = 0; v < fnumCorners; ++v) { 9470 if (fclosure[v] != faces[fOff + v]) { 9471 PetscInt v1; 9472 9473 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9474 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9475 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9476 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9477 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9478 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]); 9479 } 9480 } 9481 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9482 fOff += faceSizes[f]; 9483 } 9484 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9485 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9486 } 9487 } 9488 PetscFunctionReturn(PETSC_SUCCESS); 9489 } 9490 9491 /*@ 9492 DMPlexCheckGeometry - Check the geometry of mesh cells 9493 9494 Input Parameter: 9495 . dm - The `DMPLEX` object 9496 9497 Level: developer 9498 9499 Notes: 9500 This is a useful diagnostic when creating meshes programmatically. 9501 9502 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9503 9504 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9505 @*/ 9506 PetscErrorCode DMPlexCheckGeometry(DM dm) 9507 { 9508 Vec coordinates; 9509 PetscReal detJ, J[9], refVol = 1.0; 9510 PetscReal vol; 9511 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9512 9513 PetscFunctionBegin; 9514 PetscCall(DMGetDimension(dm, &dim)); 9515 PetscCall(DMGetCoordinateDim(dm, &dE)); 9516 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9517 PetscCall(DMPlexGetDepth(dm, &depth)); 9518 for (d = 0; d < dim; ++d) refVol *= 2.0; 9519 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9520 /* Make sure local coordinates are created, because that step is collective */ 9521 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9522 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9523 for (c = cStart; c < cEnd; ++c) { 9524 DMPolytopeType ct; 9525 PetscInt unsplit; 9526 PetscBool ignoreZeroVol = PETSC_FALSE; 9527 9528 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9529 switch (ct) { 9530 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9531 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9532 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9533 ignoreZeroVol = PETSC_TRUE; 9534 break; 9535 default: 9536 break; 9537 } 9538 switch (ct) { 9539 case DM_POLYTOPE_TRI_PRISM: 9540 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9541 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9542 case DM_POLYTOPE_PYRAMID: 9543 continue; 9544 default: 9545 break; 9546 } 9547 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9548 if (unsplit) continue; 9549 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9550 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); 9551 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9552 /* This should work with periodicity since DG coordinates should be used */ 9553 if (depth > 1) { 9554 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9555 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); 9556 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9557 } 9558 } 9559 PetscFunctionReturn(PETSC_SUCCESS); 9560 } 9561 9562 /*@ 9563 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9564 9565 Collective 9566 9567 Input Parameters: 9568 + dm - The `DMPLEX` object 9569 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9570 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9571 9572 Level: developer 9573 9574 Notes: 9575 This is mainly intended for debugging/testing purposes. 9576 9577 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9578 9579 Extra roots can come from periodic cuts, where additional points appear on the boundary 9580 9581 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9582 @*/ 9583 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9584 { 9585 PetscInt l, nleaves, nroots, overlap; 9586 const PetscInt *locals; 9587 const PetscSFNode *remotes; 9588 PetscBool distributed; 9589 MPI_Comm comm; 9590 PetscMPIInt rank; 9591 9592 PetscFunctionBegin; 9593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9594 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9595 else pointSF = dm->sf; 9596 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9597 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9598 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9599 { 9600 PetscMPIInt mpiFlag; 9601 9602 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9603 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9604 } 9605 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9606 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9607 if (!distributed) { 9608 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); 9609 PetscFunctionReturn(PETSC_SUCCESS); 9610 } 9611 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); 9612 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9613 9614 /* Check SF graph is compatible with DMPlex chart */ 9615 { 9616 PetscInt pStart, pEnd, maxLeaf; 9617 9618 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9619 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9620 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9621 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9622 } 9623 9624 /* Check Point SF has no local points referenced */ 9625 for (l = 0; l < nleaves; l++) { 9626 PetscMPIInt irank; 9627 9628 PetscCall(PetscMPIIntCast(remotes[l].rank, &irank)); 9629 PetscAssert(irank != rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%d,%" PetscInt_FMT ")", locals ? locals[l] : l, irank, remotes[l].index); 9630 } 9631 9632 /* Check there are no cells in interface */ 9633 if (!overlap) { 9634 PetscInt cellHeight, cStart, cEnd; 9635 9636 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9637 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9638 for (l = 0; l < nleaves; ++l) { 9639 const PetscInt point = locals ? locals[l] : l; 9640 9641 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9642 } 9643 } 9644 9645 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9646 { 9647 const PetscInt *rootdegree; 9648 9649 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9650 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9651 for (l = 0; l < nleaves; ++l) { 9652 const PetscInt point = locals ? locals[l] : l; 9653 const PetscInt *cone; 9654 PetscInt coneSize, c, idx; 9655 9656 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9657 PetscCall(DMPlexGetCone(dm, point, &cone)); 9658 for (c = 0; c < coneSize; ++c) { 9659 if (!rootdegree[cone[c]]) { 9660 if (locals) { 9661 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9662 } else { 9663 idx = (cone[c] < nleaves) ? cone[c] : -1; 9664 } 9665 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9666 } 9667 } 9668 } 9669 } 9670 PetscFunctionReturn(PETSC_SUCCESS); 9671 } 9672 9673 /*@ 9674 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9675 9676 Collective 9677 9678 Input Parameter: 9679 . dm - The `DMPLEX` object 9680 9681 Level: developer 9682 9683 Notes: 9684 This is mainly intended for debugging/testing purposes. 9685 9686 Other cell types which are disconnected would be caught by the symmetry and face checks. 9687 9688 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9689 9690 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9691 @*/ 9692 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9693 { 9694 PetscInt pStart, pEnd, vStart, vEnd; 9695 9696 PetscFunctionBegin; 9697 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9698 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9699 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9700 for (PetscInt v = vStart; v < vEnd; ++v) { 9701 PetscInt suppSize; 9702 9703 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9704 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9705 } 9706 PetscFunctionReturn(PETSC_SUCCESS); 9707 } 9708 9709 /*@ 9710 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9711 9712 Input Parameter: 9713 . dm - The `DMPLEX` object 9714 9715 Level: developer 9716 9717 Notes: 9718 This is a useful diagnostic when creating meshes programmatically. 9719 9720 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9721 9722 Currently does not include `DMPlexCheckCellShape()`. 9723 9724 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9725 @*/ 9726 PetscErrorCode DMPlexCheck(DM dm) 9727 { 9728 PetscInt cellHeight; 9729 9730 PetscFunctionBegin; 9731 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9732 PetscCall(DMPlexCheckSymmetry(dm)); 9733 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9734 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9735 PetscCall(DMPlexCheckGeometry(dm)); 9736 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9737 PetscCall(DMPlexCheckInterfaceCones(dm)); 9738 PetscCall(DMPlexCheckOrphanVertices(dm)); 9739 PetscFunctionReturn(PETSC_SUCCESS); 9740 } 9741 9742 typedef struct cell_stats { 9743 PetscReal min, max, sum, squaresum; 9744 PetscInt count; 9745 } cell_stats_t; 9746 9747 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9748 { 9749 PetscInt i, N = *len; 9750 9751 for (i = 0; i < N; i++) { 9752 cell_stats_t *A = (cell_stats_t *)a; 9753 cell_stats_t *B = (cell_stats_t *)b; 9754 9755 B->min = PetscMin(A->min, B->min); 9756 B->max = PetscMax(A->max, B->max); 9757 B->sum += A->sum; 9758 B->squaresum += A->squaresum; 9759 B->count += A->count; 9760 } 9761 } 9762 9763 /*@ 9764 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9765 9766 Collective 9767 9768 Input Parameters: 9769 + dm - The `DMPLEX` object 9770 . output - If true, statistics will be displayed on `stdout` 9771 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9772 9773 Level: developer 9774 9775 Notes: 9776 This is mainly intended for debugging/testing purposes. 9777 9778 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9779 9780 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9781 @*/ 9782 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9783 { 9784 DM dmCoarse; 9785 cell_stats_t stats, globalStats; 9786 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9787 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9788 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9789 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9790 PetscMPIInt rank, size; 9791 9792 PetscFunctionBegin; 9793 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9794 stats.min = PETSC_MAX_REAL; 9795 stats.max = PETSC_MIN_REAL; 9796 stats.sum = stats.squaresum = 0.; 9797 stats.count = 0; 9798 9799 PetscCallMPI(MPI_Comm_size(comm, &size)); 9800 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9801 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9802 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9803 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9804 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9805 for (c = cStart; c < cEnd; c++) { 9806 PetscInt i; 9807 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9808 9809 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9810 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9811 for (i = 0; i < PetscSqr(cdim); ++i) { 9812 frobJ += J[i] * J[i]; 9813 frobInvJ += invJ[i] * invJ[i]; 9814 } 9815 cond2 = frobJ * frobInvJ; 9816 cond = PetscSqrtReal(cond2); 9817 9818 stats.min = PetscMin(stats.min, cond); 9819 stats.max = PetscMax(stats.max, cond); 9820 stats.sum += cond; 9821 stats.squaresum += cond2; 9822 stats.count++; 9823 if (output && cond > limit) { 9824 PetscSection coordSection; 9825 Vec coordsLocal; 9826 PetscScalar *coords = NULL; 9827 PetscInt Nv, d, clSize, cl, *closure = NULL; 9828 9829 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9830 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9831 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9832 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9833 for (i = 0; i < Nv / cdim; ++i) { 9834 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9835 for (d = 0; d < cdim; ++d) { 9836 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9837 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9838 } 9839 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9840 } 9841 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9842 for (cl = 0; cl < clSize * 2; cl += 2) { 9843 const PetscInt edge = closure[cl]; 9844 9845 if ((edge >= eStart) && (edge < eEnd)) { 9846 PetscReal len; 9847 9848 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9849 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9850 } 9851 } 9852 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9853 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9854 } 9855 } 9856 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9857 9858 if (size > 1) { 9859 PetscMPIInt blockLengths[2] = {4, 1}; 9860 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9861 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9862 MPI_Op statReduce; 9863 9864 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9865 PetscCallMPI(MPI_Type_commit(&statType)); 9866 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9867 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9868 PetscCallMPI(MPI_Op_free(&statReduce)); 9869 PetscCallMPI(MPI_Type_free(&statType)); 9870 } else { 9871 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9872 } 9873 if (rank == 0) { 9874 count = globalStats.count; 9875 min = globalStats.min; 9876 max = globalStats.max; 9877 mean = globalStats.sum / globalStats.count; 9878 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9879 } 9880 9881 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)); 9882 PetscCall(PetscFree2(J, invJ)); 9883 9884 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9885 if (dmCoarse) { 9886 PetscBool isplex; 9887 9888 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9889 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9890 } 9891 PetscFunctionReturn(PETSC_SUCCESS); 9892 } 9893 9894 /*@ 9895 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9896 orthogonal quality below given tolerance. 9897 9898 Collective 9899 9900 Input Parameters: 9901 + dm - The `DMPLEX` object 9902 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9903 - atol - [0, 1] Absolute tolerance for tagging cells. 9904 9905 Output Parameters: 9906 + OrthQual - `Vec` containing orthogonal quality per cell 9907 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9908 9909 Options Database Keys: 9910 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9911 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9912 9913 Level: intermediate 9914 9915 Notes: 9916 Orthogonal quality is given by the following formula\: 9917 9918 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9919 9920 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 9921 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9922 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9923 calculating the cosine of the angle between these vectors. 9924 9925 Orthogonal quality ranges from 1 (best) to 0 (worst). 9926 9927 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9928 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9929 9930 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9931 9932 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9933 @*/ 9934 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9935 { 9936 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9937 PetscInt *idx; 9938 PetscScalar *oqVals; 9939 const PetscScalar *cellGeomArr, *faceGeomArr; 9940 PetscReal *ci, *fi, *Ai; 9941 MPI_Comm comm; 9942 Vec cellgeom, facegeom; 9943 DM dmFace, dmCell; 9944 IS glob; 9945 ISLocalToGlobalMapping ltog; 9946 PetscViewer vwr; 9947 9948 PetscFunctionBegin; 9949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9950 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9951 PetscAssertPointer(OrthQual, 4); 9952 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9953 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9954 PetscCall(DMGetDimension(dm, &nc)); 9955 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9956 { 9957 DMPlexInterpolatedFlag interpFlag; 9958 9959 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9960 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9961 PetscMPIInt rank; 9962 9963 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9964 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9965 } 9966 } 9967 if (OrthQualLabel) { 9968 PetscAssertPointer(OrthQualLabel, 5); 9969 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9970 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9971 } else { 9972 *OrthQualLabel = NULL; 9973 } 9974 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9975 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9976 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9977 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9978 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9979 PetscCall(VecCreate(comm, OrthQual)); 9980 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9981 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9982 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9983 PetscCall(VecSetUp(*OrthQual)); 9984 PetscCall(ISDestroy(&glob)); 9985 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9986 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9987 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9988 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9989 PetscCall(VecGetDM(cellgeom, &dmCell)); 9990 PetscCall(VecGetDM(facegeom, &dmFace)); 9991 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9992 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9993 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9994 PetscInt cellarr[2], *adj = NULL; 9995 PetscScalar *cArr, *fArr; 9996 PetscReal minvalc = 1.0, minvalf = 1.0; 9997 PetscFVCellGeom *cg; 9998 9999 idx[cellIter] = cell - cStart; 10000 cellarr[0] = cell; 10001 /* Make indexing into cellGeom easier */ 10002 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10003 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10004 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10005 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10006 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10007 PetscInt i; 10008 const PetscInt neigh = adj[cellneigh]; 10009 PetscReal normci = 0, normfi = 0, normai = 0; 10010 PetscFVCellGeom *cgneigh; 10011 PetscFVFaceGeom *fg; 10012 10013 /* Don't count ourselves in the neighbor list */ 10014 if (neigh == cell) continue; 10015 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10016 cellarr[1] = neigh; 10017 { 10018 PetscInt numcovpts; 10019 const PetscInt *covpts; 10020 10021 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10022 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10023 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10024 } 10025 10026 /* Compute c_i, f_i and their norms */ 10027 for (i = 0; i < nc; i++) { 10028 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10029 fi[i] = fg->centroid[i] - cg->centroid[i]; 10030 Ai[i] = fg->normal[i]; 10031 normci += PetscPowReal(ci[i], 2); 10032 normfi += PetscPowReal(fi[i], 2); 10033 normai += PetscPowReal(Ai[i], 2); 10034 } 10035 normci = PetscSqrtReal(normci); 10036 normfi = PetscSqrtReal(normfi); 10037 normai = PetscSqrtReal(normai); 10038 10039 /* Normalize and compute for each face-cell-normal pair */ 10040 for (i = 0; i < nc; i++) { 10041 ci[i] = ci[i] / normci; 10042 fi[i] = fi[i] / normfi; 10043 Ai[i] = Ai[i] / normai; 10044 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10045 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10046 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10047 } 10048 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10049 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10050 } 10051 PetscCall(PetscFree(adj)); 10052 PetscCall(PetscFree2(cArr, fArr)); 10053 /* Defer to cell if they're equal */ 10054 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10055 if (OrthQualLabel) { 10056 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10057 } 10058 } 10059 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10060 PetscCall(VecAssemblyBegin(*OrthQual)); 10061 PetscCall(VecAssemblyEnd(*OrthQual)); 10062 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10063 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10064 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10065 if (OrthQualLabel) { 10066 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10067 } 10068 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10069 PetscCall(PetscViewerDestroy(&vwr)); 10070 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10071 PetscFunctionReturn(PETSC_SUCCESS); 10072 } 10073 10074 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10075 * interpolator construction */ 10076 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10077 { 10078 PetscSection section, newSection, gsection; 10079 PetscSF sf; 10080 PetscBool hasConstraints, ghasConstraints; 10081 10082 PetscFunctionBegin; 10083 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10084 PetscAssertPointer(odm, 2); 10085 PetscCall(DMGetLocalSection(dm, §ion)); 10086 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10087 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10088 if (!ghasConstraints) { 10089 PetscCall(PetscObjectReference((PetscObject)dm)); 10090 *odm = dm; 10091 PetscFunctionReturn(PETSC_SUCCESS); 10092 } 10093 PetscCall(DMClone(dm, odm)); 10094 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10095 PetscCall(DMGetLocalSection(*odm, &newSection)); 10096 PetscCall(DMGetPointSF(*odm, &sf)); 10097 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10098 PetscCall(DMSetGlobalSection(*odm, gsection)); 10099 PetscCall(PetscSectionDestroy(&gsection)); 10100 PetscFunctionReturn(PETSC_SUCCESS); 10101 } 10102 10103 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10104 { 10105 DM dmco, dmfo; 10106 Mat interpo; 10107 Vec rscale; 10108 Vec cglobalo, clocal; 10109 Vec fglobal, fglobalo, flocal; 10110 PetscBool regular; 10111 10112 PetscFunctionBegin; 10113 PetscCall(DMGetFullDM(dmc, &dmco)); 10114 PetscCall(DMGetFullDM(dmf, &dmfo)); 10115 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10116 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10117 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10118 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10119 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10120 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10121 PetscCall(VecSet(cglobalo, 0.)); 10122 PetscCall(VecSet(clocal, 0.)); 10123 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10124 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10125 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10126 PetscCall(VecSet(fglobal, 0.)); 10127 PetscCall(VecSet(fglobalo, 0.)); 10128 PetscCall(VecSet(flocal, 0.)); 10129 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10130 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10131 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10132 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10133 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10134 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10135 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10136 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10137 *shift = fglobal; 10138 PetscCall(VecDestroy(&flocal)); 10139 PetscCall(VecDestroy(&fglobalo)); 10140 PetscCall(VecDestroy(&clocal)); 10141 PetscCall(VecDestroy(&cglobalo)); 10142 PetscCall(VecDestroy(&rscale)); 10143 PetscCall(MatDestroy(&interpo)); 10144 PetscCall(DMDestroy(&dmfo)); 10145 PetscCall(DMDestroy(&dmco)); 10146 PetscFunctionReturn(PETSC_SUCCESS); 10147 } 10148 10149 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10150 { 10151 PetscObject shifto; 10152 Vec shift; 10153 10154 PetscFunctionBegin; 10155 if (!interp) { 10156 Vec rscale; 10157 10158 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10159 PetscCall(VecDestroy(&rscale)); 10160 } else { 10161 PetscCall(PetscObjectReference((PetscObject)interp)); 10162 } 10163 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10164 if (!shifto) { 10165 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10166 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10167 shifto = (PetscObject)shift; 10168 PetscCall(VecDestroy(&shift)); 10169 } 10170 shift = (Vec)shifto; 10171 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10172 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10173 PetscCall(MatDestroy(&interp)); 10174 PetscFunctionReturn(PETSC_SUCCESS); 10175 } 10176 10177 /* Pointwise interpolation 10178 Just code FEM for now 10179 u^f = I u^c 10180 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10181 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10182 I_{ij} = psi^f_i phi^c_j 10183 */ 10184 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10185 { 10186 PetscSection gsc, gsf; 10187 PetscInt m, n; 10188 void *ctx; 10189 DM cdm; 10190 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10191 10192 PetscFunctionBegin; 10193 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10194 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10195 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10196 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10197 10198 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10199 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10200 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10201 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10202 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10203 10204 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10205 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10206 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10207 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10208 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10209 if (scaling) { 10210 /* Use naive scaling */ 10211 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10212 } 10213 PetscFunctionReturn(PETSC_SUCCESS); 10214 } 10215 10216 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10217 { 10218 VecScatter ctx; 10219 10220 PetscFunctionBegin; 10221 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10222 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10223 PetscCall(VecScatterDestroy(&ctx)); 10224 PetscFunctionReturn(PETSC_SUCCESS); 10225 } 10226 10227 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[]) 10228 { 10229 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10230 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10231 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10232 } 10233 10234 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10235 { 10236 DM dmc; 10237 PetscDS ds; 10238 Vec ones, locmass; 10239 IS cellIS; 10240 PetscFormKey key; 10241 PetscInt depth; 10242 10243 PetscFunctionBegin; 10244 PetscCall(DMClone(dm, &dmc)); 10245 PetscCall(DMCopyDisc(dm, dmc)); 10246 PetscCall(DMGetDS(dmc, &ds)); 10247 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10248 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10249 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10250 else PetscCall(DMGetLocalVector(dm, &locmass)); 10251 PetscCall(DMGetLocalVector(dm, &ones)); 10252 PetscCall(DMPlexGetDepth(dm, &depth)); 10253 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10254 PetscCall(VecSet(locmass, 0.0)); 10255 PetscCall(VecSet(ones, 1.0)); 10256 key.label = NULL; 10257 key.value = 0; 10258 key.field = 0; 10259 key.part = 0; 10260 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10261 PetscCall(ISDestroy(&cellIS)); 10262 if (mass) { 10263 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10264 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10265 } 10266 PetscCall(DMRestoreLocalVector(dm, &ones)); 10267 if (lmass) *lmass = locmass; 10268 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10269 PetscCall(DMDestroy(&dmc)); 10270 PetscFunctionReturn(PETSC_SUCCESS); 10271 } 10272 10273 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10274 { 10275 PetscSection gsc, gsf; 10276 PetscInt m, n; 10277 void *ctx; 10278 DM cdm; 10279 PetscBool regular; 10280 10281 PetscFunctionBegin; 10282 if (dmFine == dmCoarse) { 10283 DM dmc; 10284 PetscDS ds; 10285 PetscWeakForm wf; 10286 Vec u; 10287 IS cellIS; 10288 PetscFormKey key; 10289 PetscInt depth; 10290 10291 PetscCall(DMClone(dmFine, &dmc)); 10292 PetscCall(DMCopyDisc(dmFine, dmc)); 10293 PetscCall(DMGetDS(dmc, &ds)); 10294 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10295 PetscCall(PetscWeakFormClear(wf)); 10296 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10297 PetscCall(DMCreateMatrix(dmc, mass)); 10298 PetscCall(DMGetLocalVector(dmc, &u)); 10299 PetscCall(DMPlexGetDepth(dmc, &depth)); 10300 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10301 PetscCall(MatZeroEntries(*mass)); 10302 key.label = NULL; 10303 key.value = 0; 10304 key.field = 0; 10305 key.part = 0; 10306 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10307 PetscCall(ISDestroy(&cellIS)); 10308 PetscCall(DMRestoreLocalVector(dmc, &u)); 10309 PetscCall(DMDestroy(&dmc)); 10310 } else { 10311 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10312 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10313 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10314 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10315 10316 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10317 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10318 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10319 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10320 10321 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10322 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10323 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10324 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10325 } 10326 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10327 PetscFunctionReturn(PETSC_SUCCESS); 10328 } 10329 10330 /*@ 10331 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10332 10333 Input Parameter: 10334 . dm - The `DMPLEX` object 10335 10336 Output Parameter: 10337 . regular - The flag 10338 10339 Level: intermediate 10340 10341 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10342 @*/ 10343 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10344 { 10345 PetscFunctionBegin; 10346 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10347 PetscAssertPointer(regular, 2); 10348 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10349 PetscFunctionReturn(PETSC_SUCCESS); 10350 } 10351 10352 /*@ 10353 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10354 10355 Input Parameters: 10356 + dm - The `DMPLEX` object 10357 - regular - The flag 10358 10359 Level: intermediate 10360 10361 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10362 @*/ 10363 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10364 { 10365 PetscFunctionBegin; 10366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10367 ((DM_Plex *)dm->data)->regularRefinement = regular; 10368 PetscFunctionReturn(PETSC_SUCCESS); 10369 } 10370 10371 /*@ 10372 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10373 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10374 10375 Not Collective 10376 10377 Input Parameter: 10378 . dm - The `DMPLEX` object 10379 10380 Output Parameters: 10381 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10382 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10383 10384 Level: intermediate 10385 10386 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10387 @*/ 10388 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10389 { 10390 DM_Plex *plex = (DM_Plex *)dm->data; 10391 10392 PetscFunctionBegin; 10393 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10394 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10395 if (anchorSection) *anchorSection = plex->anchorSection; 10396 if (anchorIS) *anchorIS = plex->anchorIS; 10397 PetscFunctionReturn(PETSC_SUCCESS); 10398 } 10399 10400 /*@ 10401 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10402 10403 Collective 10404 10405 Input Parameters: 10406 + dm - The `DMPLEX` object 10407 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10408 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10409 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10410 10411 Level: intermediate 10412 10413 Notes: 10414 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10415 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10416 combination of other points' degrees of freedom. 10417 10418 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10419 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10420 10421 The reference counts of `anchorSection` and `anchorIS` are incremented. 10422 10423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10424 @*/ 10425 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10426 { 10427 DM_Plex *plex = (DM_Plex *)dm->data; 10428 PetscMPIInt result; 10429 10430 PetscFunctionBegin; 10431 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10432 if (anchorSection) { 10433 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10434 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10435 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10436 } 10437 if (anchorIS) { 10438 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10439 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10440 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10441 } 10442 10443 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10444 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10445 plex->anchorSection = anchorSection; 10446 10447 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10448 PetscCall(ISDestroy(&plex->anchorIS)); 10449 plex->anchorIS = anchorIS; 10450 10451 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10452 PetscInt size, a, pStart, pEnd; 10453 const PetscInt *anchors; 10454 10455 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10456 PetscCall(ISGetLocalSize(anchorIS, &size)); 10457 PetscCall(ISGetIndices(anchorIS, &anchors)); 10458 for (a = 0; a < size; a++) { 10459 PetscInt p; 10460 10461 p = anchors[a]; 10462 if (p >= pStart && p < pEnd) { 10463 PetscInt dof; 10464 10465 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10466 if (dof) { 10467 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10468 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10469 } 10470 } 10471 } 10472 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10473 } 10474 /* reset the generic constraints */ 10475 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10476 PetscFunctionReturn(PETSC_SUCCESS); 10477 } 10478 10479 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10480 { 10481 PetscSection anchorSection; 10482 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10483 10484 PetscFunctionBegin; 10485 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10486 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10487 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10488 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10489 if (numFields) { 10490 PetscInt f; 10491 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10492 10493 for (f = 0; f < numFields; f++) { 10494 PetscInt numComp; 10495 10496 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10497 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10498 } 10499 } 10500 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10501 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10502 pStart = PetscMax(pStart, sStart); 10503 pEnd = PetscMin(pEnd, sEnd); 10504 pEnd = PetscMax(pStart, pEnd); 10505 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10506 for (p = pStart; p < pEnd; p++) { 10507 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10508 if (dof) { 10509 PetscCall(PetscSectionGetDof(section, p, &dof)); 10510 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10511 for (f = 0; f < numFields; f++) { 10512 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10513 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10514 } 10515 } 10516 } 10517 PetscCall(PetscSectionSetUp(*cSec)); 10518 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10519 PetscFunctionReturn(PETSC_SUCCESS); 10520 } 10521 10522 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10523 { 10524 PetscSection aSec; 10525 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10526 const PetscInt *anchors; 10527 PetscInt numFields, f; 10528 IS aIS; 10529 MatType mtype; 10530 PetscBool iscuda, iskokkos; 10531 10532 PetscFunctionBegin; 10533 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10534 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10535 PetscCall(PetscSectionGetStorageSize(section, &n)); 10536 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10537 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10538 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10539 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10540 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10541 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10542 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10543 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10544 else mtype = MATSEQAIJ; 10545 PetscCall(MatSetType(*cMat, mtype)); 10546 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10547 PetscCall(ISGetIndices(aIS, &anchors)); 10548 /* cSec will be a subset of aSec and section */ 10549 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10550 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10551 PetscCall(PetscMalloc1(m + 1, &i)); 10552 i[0] = 0; 10553 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10554 for (p = pStart; p < pEnd; p++) { 10555 PetscInt rDof, rOff, r; 10556 10557 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10558 if (!rDof) continue; 10559 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10560 if (numFields) { 10561 for (f = 0; f < numFields; f++) { 10562 annz = 0; 10563 for (r = 0; r < rDof; r++) { 10564 a = anchors[rOff + r]; 10565 if (a < sStart || a >= sEnd) continue; 10566 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10567 annz += aDof; 10568 } 10569 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10570 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10571 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10572 } 10573 } else { 10574 annz = 0; 10575 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10576 for (q = 0; q < dof; q++) { 10577 a = anchors[rOff + q]; 10578 if (a < sStart || a >= sEnd) continue; 10579 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10580 annz += aDof; 10581 } 10582 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10583 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10584 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10585 } 10586 } 10587 nnz = i[m]; 10588 PetscCall(PetscMalloc1(nnz, &j)); 10589 offset = 0; 10590 for (p = pStart; p < pEnd; p++) { 10591 if (numFields) { 10592 for (f = 0; f < numFields; f++) { 10593 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10594 for (q = 0; q < dof; q++) { 10595 PetscInt rDof, rOff, r; 10596 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10597 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10598 for (r = 0; r < rDof; r++) { 10599 PetscInt s; 10600 10601 a = anchors[rOff + r]; 10602 if (a < sStart || a >= sEnd) continue; 10603 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10604 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10605 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10606 } 10607 } 10608 } 10609 } else { 10610 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10611 for (q = 0; q < dof; q++) { 10612 PetscInt rDof, rOff, r; 10613 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10614 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10615 for (r = 0; r < rDof; r++) { 10616 PetscInt s; 10617 10618 a = anchors[rOff + r]; 10619 if (a < sStart || a >= sEnd) continue; 10620 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10621 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10622 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10623 } 10624 } 10625 } 10626 } 10627 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10628 PetscCall(PetscFree(i)); 10629 PetscCall(PetscFree(j)); 10630 PetscCall(ISRestoreIndices(aIS, &anchors)); 10631 PetscFunctionReturn(PETSC_SUCCESS); 10632 } 10633 10634 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10635 { 10636 DM_Plex *plex = (DM_Plex *)dm->data; 10637 PetscSection anchorSection, section, cSec; 10638 Mat cMat; 10639 10640 PetscFunctionBegin; 10641 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10642 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10643 if (anchorSection) { 10644 PetscInt Nf; 10645 10646 PetscCall(DMGetLocalSection(dm, §ion)); 10647 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10648 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10649 PetscCall(DMGetNumFields(dm, &Nf)); 10650 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10651 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10652 PetscCall(PetscSectionDestroy(&cSec)); 10653 PetscCall(MatDestroy(&cMat)); 10654 } 10655 PetscFunctionReturn(PETSC_SUCCESS); 10656 } 10657 10658 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10659 { 10660 IS subis; 10661 PetscSection section, subsection; 10662 10663 PetscFunctionBegin; 10664 PetscCall(DMGetLocalSection(dm, §ion)); 10665 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10666 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10667 /* Create subdomain */ 10668 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10669 /* Create submodel */ 10670 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10671 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10672 PetscCall(DMSetLocalSection(*subdm, subsection)); 10673 PetscCall(PetscSectionDestroy(&subsection)); 10674 PetscCall(DMCopyDisc(dm, *subdm)); 10675 /* Create map from submodel to global model */ 10676 if (is) { 10677 PetscSection sectionGlobal, subsectionGlobal; 10678 IS spIS; 10679 const PetscInt *spmap; 10680 PetscInt *subIndices; 10681 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10682 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10683 10684 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10685 PetscCall(ISGetIndices(spIS, &spmap)); 10686 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10687 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10688 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10689 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10690 for (p = pStart; p < pEnd; ++p) { 10691 PetscInt gdof, pSubSize = 0; 10692 10693 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10694 if (gdof > 0) { 10695 for (f = 0; f < Nf; ++f) { 10696 PetscInt fdof, fcdof; 10697 10698 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10699 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10700 pSubSize += fdof - fcdof; 10701 } 10702 subSize += pSubSize; 10703 if (pSubSize) { 10704 if (bs < 0) { 10705 bs = pSubSize; 10706 } else if (bs != pSubSize) { 10707 /* Layout does not admit a pointwise block size */ 10708 bs = 1; 10709 } 10710 } 10711 } 10712 } 10713 /* Must have same blocksize on all procs (some might have no points) */ 10714 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10715 bsLocal[1] = bs; 10716 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10717 if (bsMinMax[0] != bsMinMax[1]) { 10718 bs = 1; 10719 } else { 10720 bs = bsMinMax[0]; 10721 } 10722 PetscCall(PetscMalloc1(subSize, &subIndices)); 10723 for (p = pStart; p < pEnd; ++p) { 10724 PetscInt gdof, goff; 10725 10726 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10727 if (gdof > 0) { 10728 const PetscInt point = spmap[p]; 10729 10730 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10731 for (f = 0; f < Nf; ++f) { 10732 PetscInt fdof, fcdof, fc, f2, poff = 0; 10733 10734 /* Can get rid of this loop by storing field information in the global section */ 10735 for (f2 = 0; f2 < f; ++f2) { 10736 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10737 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10738 poff += fdof - fcdof; 10739 } 10740 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10741 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10742 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10743 } 10744 } 10745 } 10746 PetscCall(ISRestoreIndices(spIS, &spmap)); 10747 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10748 if (bs > 1) { 10749 /* We need to check that the block size does not come from non-contiguous fields */ 10750 PetscInt i, j, set = 1; 10751 for (i = 0; i < subSize; i += bs) { 10752 for (j = 0; j < bs; ++j) { 10753 if (subIndices[i + j] != subIndices[i] + j) { 10754 set = 0; 10755 break; 10756 } 10757 } 10758 } 10759 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10760 } 10761 /* Attach nullspace */ 10762 for (f = 0; f < Nf; ++f) { 10763 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10764 if ((*subdm)->nullspaceConstructors[f]) break; 10765 } 10766 if (f < Nf) { 10767 MatNullSpace nullSpace; 10768 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10769 10770 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10771 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10772 } 10773 } 10774 PetscFunctionReturn(PETSC_SUCCESS); 10775 } 10776 10777 /*@ 10778 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10779 10780 Input Parameters: 10781 + dm - The `DM` 10782 - dummy - unused argument 10783 10784 Options Database Key: 10785 . -dm_plex_monitor_throughput - Activate the monitor 10786 10787 Level: developer 10788 10789 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10790 @*/ 10791 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10792 { 10793 PetscLogHandler default_handler; 10794 10795 PetscFunctionBegin; 10796 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10797 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10798 if (default_handler) { 10799 PetscLogEvent event; 10800 PetscEventPerfInfo eventInfo; 10801 PetscLogDouble cellRate, flopRate; 10802 PetscInt cStart, cEnd, Nf, N; 10803 const char *name; 10804 10805 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10806 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10807 PetscCall(DMGetNumFields(dm, &Nf)); 10808 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10809 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10810 N = (cEnd - cStart) * Nf * eventInfo.count; 10811 flopRate = eventInfo.flops / eventInfo.time; 10812 cellRate = N / eventInfo.time; 10813 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)); 10814 } else { 10815 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."); 10816 } 10817 PetscFunctionReturn(PETSC_SUCCESS); 10818 } 10819