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 12 /* Logging support */ 13 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_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; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 15 16 PetscBool Plexcite = PETSC_FALSE; 17 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 18 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 19 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 20 "journal = {SIAM Journal on Scientific Computing},\n" 21 "volume = {38},\n" 22 "number = {5},\n" 23 "pages = {S143--S155},\n" 24 "eprint = {http://arxiv.org/abs/1506.07749},\n" 25 "doi = {10.1137/15M1026092},\n" 26 "year = {2016},\n" 27 "petsc_uses={DMPlex},\n}\n"; 28 29 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 30 31 /*@ 32 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 33 34 Input Parameter: 35 . dm - The `DMPLEX` object 36 37 Output Parameter: 38 . simplex - Flag checking for a simplex 39 40 Level: intermediate 41 42 Note: 43 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 44 If the mesh has no cells, this returns `PETSC_FALSE`. 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 47 @*/ 48 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 49 { 50 DMPolytopeType ct; 51 PetscInt cStart, cEnd; 52 53 PetscFunctionBegin; 54 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 55 if (cEnd <= cStart) { 56 *simplex = PETSC_FALSE; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 60 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@ 65 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 66 67 Input Parameters: 68 + dm - The `DMPLEX` object 69 - height - The cell height in the Plex, 0 is the default 70 71 Output Parameters: 72 + cStart - The first "normal" cell 73 - cEnd - The upper bound on "normal"" cells 74 75 Level: developer 76 77 Note: 78 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 79 80 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 81 @*/ 82 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 83 { 84 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 85 PetscInt cS, cE, c; 86 87 PetscFunctionBegin; 88 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 89 for (c = cS; c < cE; ++c) { 90 DMPolytopeType cct; 91 92 PetscCall(DMPlexGetCellType(dm, c, &cct)); 93 if ((PetscInt)cct < 0) break; 94 switch (cct) { 95 case DM_POLYTOPE_POINT: 96 case DM_POLYTOPE_SEGMENT: 97 case DM_POLYTOPE_TRIANGLE: 98 case DM_POLYTOPE_QUADRILATERAL: 99 case DM_POLYTOPE_TETRAHEDRON: 100 case DM_POLYTOPE_HEXAHEDRON: 101 ct = cct; 102 break; 103 default: 104 break; 105 } 106 if (ct != DM_POLYTOPE_UNKNOWN) break; 107 } 108 if (ct != DM_POLYTOPE_UNKNOWN) { 109 DMLabel ctLabel; 110 111 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 112 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 113 // Reset label for fast lookup 114 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 115 } 116 if (cStart) *cStart = cS; 117 if (cEnd) *cEnd = cE; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 122 { 123 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 124 PetscInt *sStart, *sEnd; 125 PetscViewerVTKFieldType *ft; 126 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 127 DMLabel depthLabel, ctLabel; 128 129 PetscFunctionBegin; 130 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 162 } 163 164 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 165 *types = 0; 166 167 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 168 if (globalvcdof[c]) ++(*types); 169 } 170 171 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 172 t = 0; 173 if (globalvcdof[DM_NUM_POLYTOPES]) { 174 sStart[t] = vStart; 175 sEnd[t] = vEnd; 176 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 177 ++t; 178 } 179 180 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 181 if (globalvcdof[c]) { 182 const DMPolytopeType ict = (DMPolytopeType)c; 183 184 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 185 sStart[t] = cStart; 186 sEnd[t] = cEnd; 187 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 188 ++t; 189 } 190 } 191 192 if (!(*types)) { 193 if (field >= 0) { 194 const char *fieldname; 195 196 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 197 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 198 } else { 199 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 200 } 201 } 202 203 *ssStart = sStart; 204 *ssEnd = sEnd; 205 *sft = ft; 206 PetscFunctionReturn(PETSC_SUCCESS); 207 } 208 209 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 210 { 211 PetscFunctionBegin; 212 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 213 PetscFunctionReturn(PETSC_SUCCESS); 214 } 215 216 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 217 { 218 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 219 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 220 221 PetscFunctionBegin; 222 *ft = PETSC_VTK_INVALID; 223 PetscCall(DMGetCoordinateDim(dm, &cdim)); 224 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 225 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 226 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 227 if (field >= 0) { 228 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 229 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 230 } else { 231 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 232 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 233 } 234 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 235 if (globalvcdof[0]) { 236 *sStart = vStart; 237 *sEnd = vEnd; 238 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 239 else *ft = PETSC_VTK_POINT_FIELD; 240 } else if (globalvcdof[1]) { 241 *sStart = cStart; 242 *sEnd = cEnd; 243 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 244 else *ft = PETSC_VTK_CELL_FIELD; 245 } else { 246 if (field >= 0) { 247 const char *fieldname; 248 249 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 250 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 251 } else { 252 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 253 } 254 } 255 PetscFunctionReturn(PETSC_SUCCESS); 256 } 257 258 /*@ 259 DMPlexVecView1D - Plot many 1D solutions on the same line graph 260 261 Collective 262 263 Input Parameters: 264 + dm - The `DMPLEX` object 265 . n - The number of vectors 266 . u - The array of local vectors 267 - viewer - The `PetscViewer` 268 269 Level: advanced 270 271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 272 @*/ 273 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 274 { 275 PetscDS ds; 276 PetscDraw draw = NULL; 277 PetscDrawLG lg; 278 Vec coordinates; 279 const PetscScalar *coords, **sol; 280 PetscReal *vals; 281 PetscInt *Nc; 282 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 283 char **names; 284 285 PetscFunctionBegin; 286 PetscCall(DMGetDS(dm, &ds)); 287 PetscCall(PetscDSGetNumFields(ds, &Nf)); 288 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 289 PetscCall(PetscDSGetComponents(ds, &Nc)); 290 291 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 292 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 293 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 294 295 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 296 for (i = 0, l = 0; i < n; ++i) { 297 const char *vname; 298 299 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 300 for (f = 0; f < Nf; ++f) { 301 PetscObject disc; 302 const char *fname; 303 char tmpname[PETSC_MAX_PATH_LEN]; 304 305 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 306 /* TODO Create names for components */ 307 for (c = 0; c < Nc[f]; ++c, ++l) { 308 PetscCall(PetscObjectGetName(disc, &fname)); 309 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 312 PetscCall(PetscStrallocpy(tmpname, &names[l])); 313 } 314 } 315 } 316 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 317 /* Just add P_1 support for now */ 318 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 319 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 320 PetscCall(VecGetArrayRead(coordinates, &coords)); 321 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 322 for (v = vStart; v < vEnd; ++v) { 323 PetscScalar *x, *svals; 324 325 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 326 for (i = 0; i < n; ++i) { 327 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 328 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 329 } 330 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 331 } 332 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 333 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 334 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 335 PetscCall(PetscFree3(sol, names, vals)); 336 337 PetscCall(PetscDrawLGDraw(lg)); 338 PetscCall(PetscDrawLGDestroy(&lg)); 339 PetscFunctionReturn(PETSC_SUCCESS); 340 } 341 342 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 343 { 344 DM dm; 345 346 PetscFunctionBegin; 347 PetscCall(VecGetDM(u, &dm)); 348 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 349 PetscFunctionReturn(PETSC_SUCCESS); 350 } 351 352 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 353 { 354 DM dm; 355 PetscSection s; 356 PetscDraw draw, popup; 357 DM cdm; 358 PetscSection coordSection; 359 Vec coordinates; 360 const PetscScalar *array; 361 PetscReal lbound[3], ubound[3]; 362 PetscReal vbound[2], time; 363 PetscBool flg; 364 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 365 const char *name; 366 char title[PETSC_MAX_PATH_LEN]; 367 368 PetscFunctionBegin; 369 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 370 PetscCall(VecGetDM(v, &dm)); 371 PetscCall(DMGetCoordinateDim(dm, &dim)); 372 PetscCall(DMGetLocalSection(dm, &s)); 373 PetscCall(PetscSectionGetNumFields(s, &Nf)); 374 PetscCall(DMGetCoarsenLevel(dm, &level)); 375 PetscCall(DMGetCoordinateDM(dm, &cdm)); 376 PetscCall(DMGetLocalSection(cdm, &coordSection)); 377 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 378 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 379 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 380 381 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 382 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 383 384 PetscCall(VecGetLocalSize(coordinates, &N)); 385 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 386 PetscCall(PetscDrawClear(draw)); 387 388 /* Could implement something like DMDASelectFields() */ 389 for (f = 0; f < Nf; ++f) { 390 DM fdm = dm; 391 Vec fv = v; 392 IS fis; 393 char prefix[PETSC_MAX_PATH_LEN]; 394 const char *fname; 395 396 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 397 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 398 399 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 400 else prefix[0] = '\0'; 401 if (Nf > 1) { 402 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 403 PetscCall(VecGetSubVector(v, fis, &fv)); 404 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 405 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 406 } 407 for (comp = 0; comp < Nc; ++comp, ++w) { 408 PetscInt nmax = 2; 409 410 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 411 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 412 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 413 PetscCall(PetscDrawSetTitle(draw, title)); 414 415 /* TODO Get max and min only for this component */ 416 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 417 if (!flg) { 418 PetscCall(VecMin(fv, NULL, &vbound[0])); 419 PetscCall(VecMax(fv, NULL, &vbound[1])); 420 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 421 } 422 423 PetscCall(PetscDrawGetPopup(draw, &popup)); 424 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 425 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 426 PetscCall(VecGetArrayRead(fv, &array)); 427 for (c = cStart; c < cEnd; ++c) { 428 PetscScalar *coords = NULL, *a = NULL; 429 const PetscScalar *coords_arr; 430 PetscBool isDG; 431 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 432 433 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 434 if (a) { 435 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 436 color[1] = color[2] = color[3] = color[0]; 437 } else { 438 PetscScalar *vals = NULL; 439 PetscInt numVals, va; 440 441 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 442 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); 443 switch (numVals / Nc) { 444 case 3: /* P1 Triangle */ 445 case 4: /* P1 Quadrangle */ 446 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 447 break; 448 case 6: /* P2 Triangle */ 449 case 8: /* P2 Quadrangle */ 450 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 451 break; 452 default: 453 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 454 } 455 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 456 } 457 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 458 switch (numCoords) { 459 case 6: 460 case 12: /* Localized triangle */ 461 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])); 462 break; 463 case 8: 464 case 16: /* Localized quadrilateral */ 465 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])); 466 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])); 467 break; 468 default: 469 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 470 } 471 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 472 } 473 PetscCall(VecRestoreArrayRead(fv, &array)); 474 PetscCall(PetscDrawFlush(draw)); 475 PetscCall(PetscDrawPause(draw)); 476 PetscCall(PetscDrawSave(draw)); 477 } 478 if (Nf > 1) { 479 PetscCall(VecRestoreSubVector(v, fis, &fv)); 480 PetscCall(ISDestroy(&fis)); 481 PetscCall(DMDestroy(&fdm)); 482 } 483 } 484 PetscFunctionReturn(PETSC_SUCCESS); 485 } 486 487 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 488 { 489 DM dm; 490 PetscDraw draw; 491 PetscInt dim; 492 PetscBool isnull; 493 494 PetscFunctionBegin; 495 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 496 PetscCall(PetscDrawIsNull(draw, &isnull)); 497 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 498 499 PetscCall(VecGetDM(v, &dm)); 500 PetscCall(DMGetCoordinateDim(dm, &dim)); 501 switch (dim) { 502 case 1: 503 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 504 break; 505 case 2: 506 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 507 break; 508 default: 509 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 510 } 511 PetscFunctionReturn(PETSC_SUCCESS); 512 } 513 514 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 515 { 516 DM dm; 517 Vec locv; 518 const char *name; 519 PetscSection section; 520 PetscInt pStart, pEnd; 521 PetscInt numFields; 522 PetscViewerVTKFieldType ft; 523 524 PetscFunctionBegin; 525 PetscCall(VecGetDM(v, &dm)); 526 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 527 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 528 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 529 PetscCall(VecCopy(v, locv)); 530 PetscCall(DMGetLocalSection(dm, §ion)); 531 PetscCall(PetscSectionGetNumFields(section, &numFields)); 532 if (!numFields) { 533 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 534 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 535 } else { 536 PetscInt f; 537 538 for (f = 0; f < numFields; f++) { 539 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 540 if (ft == PETSC_VTK_INVALID) continue; 541 PetscCall(PetscObjectReference((PetscObject)locv)); 542 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 543 } 544 PetscCall(VecDestroy(&locv)); 545 } 546 PetscFunctionReturn(PETSC_SUCCESS); 547 } 548 549 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 550 { 551 DM dm; 552 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 553 554 PetscFunctionBegin; 555 PetscCall(VecGetDM(v, &dm)); 556 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 562 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 563 PetscInt i, numFields; 564 PetscObject fe; 565 PetscBool fem = PETSC_FALSE; 566 Vec locv = v; 567 const char *name; 568 PetscInt step; 569 PetscReal time; 570 571 PetscCall(DMGetNumFields(dm, &numFields)); 572 for (i = 0; i < numFields; i++) { 573 PetscCall(DMGetField(dm, i, NULL, &fe)); 574 if (fe->classid == PETSCFE_CLASSID) { 575 fem = PETSC_TRUE; 576 break; 577 } 578 } 579 if (fem) { 580 PetscObject isZero; 581 582 PetscCall(DMGetLocalVector(dm, &locv)); 583 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 584 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 585 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 586 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 587 PetscCall(VecCopy(v, locv)); 588 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 589 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 590 } 591 if (isvtk) { 592 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 593 } else if (ishdf5) { 594 #if defined(PETSC_HAVE_HDF5) 595 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 596 #else 597 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 598 #endif 599 } else if (isdraw) { 600 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 601 } else if (isglvis) { 602 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 603 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 604 PetscCall(VecView_GLVis(locv, viewer)); 605 } else if (iscgns) { 606 #if defined(PETSC_HAVE_CGNS) 607 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 608 #else 609 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 610 #endif 611 } 612 if (fem) { 613 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 614 PetscCall(DMRestoreLocalVector(dm, &locv)); 615 } 616 } else { 617 PetscBool isseq; 618 619 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 620 if (isseq) PetscCall(VecView_Seq(v, viewer)); 621 else PetscCall(VecView_MPI(v, viewer)); 622 } 623 PetscFunctionReturn(PETSC_SUCCESS); 624 } 625 626 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 627 { 628 DM dm; 629 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 630 631 PetscFunctionBegin; 632 PetscCall(VecGetDM(v, &dm)); 633 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (isvtk || isdraw || isglvis || iscgns) { 641 Vec locv; 642 PetscObject isZero; 643 const char *name; 644 645 PetscCall(DMGetLocalVector(dm, &locv)); 646 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 647 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 648 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 649 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 650 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 651 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 652 PetscCall(VecView_Plex_Local(locv, viewer)); 653 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 654 PetscCall(DMRestoreLocalVector(dm, &locv)); 655 } else if (ishdf5) { 656 #if defined(PETSC_HAVE_HDF5) 657 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 658 #else 659 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 660 #endif 661 } else if (isexodusii) { 662 #if defined(PETSC_HAVE_EXODUSII) 663 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 664 #else 665 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 666 #endif 667 } else { 668 PetscBool isseq; 669 670 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 671 if (isseq) PetscCall(VecView_Seq(v, viewer)); 672 else PetscCall(VecView_MPI(v, viewer)); 673 } 674 PetscFunctionReturn(PETSC_SUCCESS); 675 } 676 677 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 678 { 679 DM dm; 680 MPI_Comm comm; 681 PetscViewerFormat format; 682 Vec v; 683 PetscBool isvtk, ishdf5; 684 685 PetscFunctionBegin; 686 PetscCall(VecGetDM(originalv, &dm)); 687 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 688 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 689 PetscCall(PetscViewerGetFormat(viewer, &format)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 692 if (format == PETSC_VIEWER_NATIVE) { 693 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 694 /* this need a better fix */ 695 if (dm->useNatural) { 696 if (dm->sfNatural) { 697 const char *vecname; 698 PetscInt n, nroots; 699 700 PetscCall(VecGetLocalSize(originalv, &n)); 701 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 702 if (n == nroots) { 703 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 704 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 705 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 706 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 707 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 709 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 710 } else v = originalv; 711 } else v = originalv; 712 713 if (ishdf5) { 714 #if defined(PETSC_HAVE_HDF5) 715 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 716 #else 717 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 718 #endif 719 } else if (isvtk) { 720 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 721 } else { 722 PetscBool isseq; 723 724 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 725 if (isseq) PetscCall(VecView_Seq(v, viewer)); 726 else PetscCall(VecView_MPI(v, viewer)); 727 } 728 if (v != originalv) PetscCall(VecDestroy(&v)); 729 PetscFunctionReturn(PETSC_SUCCESS); 730 } 731 732 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 733 { 734 DM dm; 735 PetscBool ishdf5; 736 737 PetscFunctionBegin; 738 PetscCall(VecGetDM(v, &dm)); 739 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 740 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 741 if (ishdf5) { 742 DM dmBC; 743 Vec gv; 744 const char *name; 745 746 PetscCall(DMGetOutputDM(dm, &dmBC)); 747 PetscCall(DMGetGlobalVector(dmBC, &gv)); 748 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 749 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 750 PetscCall(VecLoad_Default(gv, viewer)); 751 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 753 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 754 } else PetscCall(VecLoad_Default(v, viewer)); 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 759 { 760 DM dm; 761 PetscBool ishdf5, isexodusii; 762 763 PetscFunctionBegin; 764 PetscCall(VecGetDM(v, &dm)); 765 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 768 if (ishdf5) { 769 #if defined(PETSC_HAVE_HDF5) 770 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 771 #else 772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 773 #endif 774 } else if (isexodusii) { 775 #if defined(PETSC_HAVE_EXODUSII) 776 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 777 #else 778 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 779 #endif 780 } else PetscCall(VecLoad_Default(v, viewer)); 781 PetscFunctionReturn(PETSC_SUCCESS); 782 } 783 784 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 785 { 786 DM dm; 787 PetscViewerFormat format; 788 PetscBool ishdf5; 789 790 PetscFunctionBegin; 791 PetscCall(VecGetDM(originalv, &dm)); 792 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 793 PetscCall(PetscViewerGetFormat(viewer, &format)); 794 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 795 if (format == PETSC_VIEWER_NATIVE) { 796 if (dm->useNatural) { 797 if (dm->sfNatural) { 798 if (ishdf5) { 799 #if defined(PETSC_HAVE_HDF5) 800 Vec v; 801 const char *vecname; 802 803 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 804 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 805 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 806 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 807 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 808 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 809 PetscCall(VecDestroy(&v)); 810 #else 811 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 812 #endif 813 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 814 } 815 } else PetscCall(VecLoad_Default(originalv, viewer)); 816 } 817 PetscFunctionReturn(PETSC_SUCCESS); 818 } 819 820 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 821 { 822 PetscSection coordSection; 823 Vec coordinates; 824 DMLabel depthLabel, celltypeLabel; 825 const char *name[4]; 826 const PetscScalar *a; 827 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 828 829 PetscFunctionBegin; 830 PetscCall(DMGetDimension(dm, &dim)); 831 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 832 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 833 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 834 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 835 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 836 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 837 PetscCall(VecGetArrayRead(coordinates, &a)); 838 name[0] = "vertex"; 839 name[1] = "edge"; 840 name[dim - 1] = "face"; 841 name[dim] = "cell"; 842 for (c = cStart; c < cEnd; ++c) { 843 PetscInt *closure = NULL; 844 PetscInt closureSize, cl, ct; 845 846 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 847 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 848 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 849 PetscCall(PetscViewerASCIIPushTab(viewer)); 850 for (cl = 0; cl < closureSize * 2; cl += 2) { 851 PetscInt point = closure[cl], depth, dof, off, d, p; 852 853 if ((point < pStart) || (point >= pEnd)) continue; 854 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 855 if (!dof) continue; 856 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 857 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 859 for (p = 0; p < dof / dim; ++p) { 860 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 861 for (d = 0; d < dim; ++d) { 862 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 863 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 864 } 865 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 866 } 867 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 868 } 869 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 870 PetscCall(PetscViewerASCIIPopTab(viewer)); 871 } 872 PetscCall(VecRestoreArrayRead(coordinates, &a)); 873 PetscFunctionReturn(PETSC_SUCCESS); 874 } 875 876 typedef enum { 877 CS_CARTESIAN, 878 CS_POLAR, 879 CS_CYLINDRICAL, 880 CS_SPHERICAL 881 } CoordSystem; 882 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 883 884 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 885 { 886 PetscInt i; 887 888 PetscFunctionBegin; 889 if (dim > 3) { 890 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 891 } else { 892 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 893 894 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 895 switch (cs) { 896 case CS_CARTESIAN: 897 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 898 break; 899 case CS_POLAR: 900 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 901 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 902 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 903 break; 904 case CS_CYLINDRICAL: 905 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 906 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 907 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 908 trcoords[2] = coords[2]; 909 break; 910 case CS_SPHERICAL: 911 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 912 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 913 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 914 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 915 break; 916 } 917 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 918 } 919 PetscFunctionReturn(PETSC_SUCCESS); 920 } 921 922 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 923 { 924 DM_Plex *mesh = (DM_Plex *)dm->data; 925 DM cdm, cdmCell; 926 PetscSection coordSection, coordSectionCell; 927 Vec coordinates, coordinatesCell; 928 PetscViewerFormat format; 929 930 PetscFunctionBegin; 931 PetscCall(PetscViewerGetFormat(viewer, &format)); 932 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 933 const char *name; 934 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 935 PetscInt pStart, pEnd, p, numLabels, l; 936 PetscMPIInt rank, size; 937 938 PetscCall(DMGetCoordinateDM(dm, &cdm)); 939 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 940 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 941 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 942 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 943 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 944 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 945 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 946 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 947 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 949 PetscCall(DMGetDimension(dm, &dim)); 950 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 951 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 952 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 953 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 955 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 956 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 957 for (p = pStart; p < pEnd; ++p) { 958 PetscInt dof, off, s; 959 960 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 961 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 962 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 963 } 964 PetscCall(PetscViewerFlush(viewer)); 965 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 966 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 967 for (p = pStart; p < pEnd; ++p) { 968 PetscInt dof, off, c; 969 970 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 971 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 972 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])); 973 } 974 PetscCall(PetscViewerFlush(viewer)); 975 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 976 if (coordSection && coordinates) { 977 CoordSystem cs = CS_CARTESIAN; 978 const PetscScalar *array, *arrayCell = NULL; 979 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 980 PetscMPIInt rank; 981 const char *name; 982 983 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 984 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 985 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 986 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 987 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 988 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 989 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 990 pStart = PetscMin(pvStart, pcStart); 991 pEnd = PetscMax(pvEnd, pcEnd); 992 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 994 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 995 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 996 997 PetscCall(VecGetArrayRead(coordinates, &array)); 998 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 999 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1000 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1001 for (p = pStart; p < pEnd; ++p) { 1002 PetscInt dof, off; 1003 1004 if (p >= pvStart && p < pvEnd) { 1005 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1006 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1007 if (dof) { 1008 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1009 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1010 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1011 } 1012 } 1013 if (cdmCell && p >= pcStart && p < pcEnd) { 1014 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1015 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1016 if (dof) { 1017 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1018 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1019 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1020 } 1021 } 1022 } 1023 PetscCall(PetscViewerFlush(viewer)); 1024 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1025 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1026 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1027 } 1028 PetscCall(DMGetNumLabels(dm, &numLabels)); 1029 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1030 for (l = 0; l < numLabels; ++l) { 1031 DMLabel label; 1032 PetscBool isdepth; 1033 const char *name; 1034 1035 PetscCall(DMGetLabelName(dm, l, &name)); 1036 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1037 if (isdepth) continue; 1038 PetscCall(DMGetLabel(dm, name, &label)); 1039 PetscCall(DMLabelView(label, viewer)); 1040 } 1041 if (size > 1) { 1042 PetscSF sf; 1043 1044 PetscCall(DMGetPointSF(dm, &sf)); 1045 PetscCall(PetscSFView(sf, viewer)); 1046 } 1047 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 1048 PetscCall(PetscViewerFlush(viewer)); 1049 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1050 const char *name, *color; 1051 const char *defcolors[3] = {"gray", "orange", "green"}; 1052 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1053 char lname[PETSC_MAX_PATH_LEN]; 1054 PetscReal scale = 2.0; 1055 PetscReal tikzscale = 1.0; 1056 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1057 double tcoords[3]; 1058 PetscScalar *coords; 1059 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 1060 PetscMPIInt rank, size; 1061 char **names, **colors, **lcolors; 1062 PetscBool flg, lflg; 1063 PetscBT wp = NULL; 1064 PetscInt pEnd, pStart; 1065 1066 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1069 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1070 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1071 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1072 PetscCall(DMGetDimension(dm, &dim)); 1073 PetscCall(DMPlexGetDepth(dm, &depth)); 1074 PetscCall(DMGetNumLabels(dm, &numLabels)); 1075 numLabels = PetscMax(numLabels, 10); 1076 numColors = 10; 1077 numLColors = 10; 1078 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1080 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1081 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1082 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1083 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1084 n = 4; 1085 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1086 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1087 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1088 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1089 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1090 if (!useLabels) numLabels = 0; 1091 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1092 if (!useColors) { 1093 numColors = 3; 1094 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1095 } 1096 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1097 if (!useColors) { 1098 numLColors = 4; 1099 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1100 } 1101 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1102 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1103 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1104 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1105 if (depth < dim) plotEdges = PETSC_FALSE; 1106 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1107 1108 /* filter points with labelvalue != labeldefaultvalue */ 1109 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1110 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1112 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1113 if (lflg) { 1114 DMLabel lbl; 1115 1116 PetscCall(DMGetLabel(dm, lname, &lbl)); 1117 if (lbl) { 1118 PetscInt val, defval; 1119 1120 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1121 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1122 for (c = pStart; c < pEnd; c++) { 1123 PetscInt *closure = NULL; 1124 PetscInt closureSize; 1125 1126 PetscCall(DMLabelGetValue(lbl, c, &val)); 1127 if (val == defval) continue; 1128 1129 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1130 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1131 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1132 } 1133 } 1134 } 1135 1136 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1137 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1138 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1139 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1140 \\documentclass[tikz]{standalone}\n\n\ 1141 \\usepackage{pgflibraryshapes}\n\ 1142 \\usetikzlibrary{backgrounds}\n\ 1143 \\usetikzlibrary{arrows}\n\ 1144 \\begin{document}\n")); 1145 if (size > 1) { 1146 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1147 for (p = 0; p < size; ++p) { 1148 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1149 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1150 } 1151 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1152 } 1153 if (drawHasse) { 1154 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1155 1156 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1168 } 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1170 1171 /* Plot vertices */ 1172 PetscCall(VecGetArray(coordinates, &coords)); 1173 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1174 for (v = vStart; v < vEnd; ++v) { 1175 PetscInt off, dof, d; 1176 PetscBool isLabeled = PETSC_FALSE; 1177 1178 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1179 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1180 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1181 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1182 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1183 for (d = 0; d < dof; ++d) { 1184 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1185 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1186 } 1187 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1188 if (dim == 3) { 1189 PetscReal tmp = tcoords[1]; 1190 tcoords[1] = tcoords[2]; 1191 tcoords[2] = -tmp; 1192 } 1193 for (d = 0; d < dof; ++d) { 1194 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1195 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1196 } 1197 if (drawHasse) color = colors[0 % numColors]; 1198 else color = colors[rank % numColors]; 1199 for (l = 0; l < numLabels; ++l) { 1200 PetscInt val; 1201 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1202 if (val >= 0) { 1203 color = lcolors[l % numLColors]; 1204 isLabeled = PETSC_TRUE; 1205 break; 1206 } 1207 } 1208 if (drawNumbers[0]) { 1209 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1210 } else if (drawColors[0]) { 1211 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1212 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1213 } 1214 PetscCall(VecRestoreArray(coordinates, &coords)); 1215 PetscCall(PetscViewerFlush(viewer)); 1216 /* Plot edges */ 1217 if (plotEdges) { 1218 PetscCall(VecGetArray(coordinates, &coords)); 1219 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1220 for (e = eStart; e < eEnd; ++e) { 1221 const PetscInt *cone; 1222 PetscInt coneSize, offA, offB, dof, d; 1223 1224 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1225 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1226 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1227 PetscCall(DMPlexGetCone(dm, e, &cone)); 1228 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1229 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1230 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1231 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1232 for (d = 0; d < dof; ++d) { 1233 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1234 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1235 } 1236 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1237 if (dim == 3) { 1238 PetscReal tmp = tcoords[1]; 1239 tcoords[1] = tcoords[2]; 1240 tcoords[2] = -tmp; 1241 } 1242 for (d = 0; d < dof; ++d) { 1243 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1244 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1245 } 1246 if (drawHasse) color = colors[1 % numColors]; 1247 else color = colors[rank % numColors]; 1248 for (l = 0; l < numLabels; ++l) { 1249 PetscInt val; 1250 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1251 if (val >= 0) { 1252 color = lcolors[l % numLColors]; 1253 break; 1254 } 1255 } 1256 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1257 } 1258 PetscCall(VecRestoreArray(coordinates, &coords)); 1259 PetscCall(PetscViewerFlush(viewer)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1261 } 1262 /* Plot cells */ 1263 if (dim == 3 || !drawNumbers[1]) { 1264 for (e = eStart; e < eEnd; ++e) { 1265 const PetscInt *cone; 1266 1267 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1268 color = colors[rank % numColors]; 1269 for (l = 0; l < numLabels; ++l) { 1270 PetscInt val; 1271 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1272 if (val >= 0) { 1273 color = lcolors[l % numLColors]; 1274 break; 1275 } 1276 } 1277 PetscCall(DMPlexGetCone(dm, e, &cone)); 1278 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1279 } 1280 } else { 1281 DMPolytopeType ct; 1282 1283 /* Drawing a 2D polygon */ 1284 for (c = cStart; c < cEnd; ++c) { 1285 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1286 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1287 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1288 const PetscInt *cone; 1289 PetscInt coneSize, e; 1290 1291 PetscCall(DMPlexGetCone(dm, c, &cone)); 1292 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1293 for (e = 0; e < coneSize; ++e) { 1294 const PetscInt *econe; 1295 1296 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1297 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)); 1298 } 1299 } else { 1300 PetscInt *closure = NULL; 1301 PetscInt closureSize, Nv = 0, v; 1302 1303 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1304 for (p = 0; p < closureSize * 2; p += 2) { 1305 const PetscInt point = closure[p]; 1306 1307 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1308 } 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1310 for (v = 0; v <= Nv; ++v) { 1311 const PetscInt vertex = closure[v % Nv]; 1312 1313 if (v > 0) { 1314 if (plotEdges) { 1315 const PetscInt *edge; 1316 PetscInt endpoints[2], ne; 1317 1318 endpoints[0] = closure[v - 1]; 1319 endpoints[1] = vertex; 1320 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1321 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1322 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1323 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1324 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1325 } 1326 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1327 } 1328 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1329 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1330 } 1331 } 1332 } 1333 for (c = cStart; c < cEnd; ++c) { 1334 double ccoords[3] = {0.0, 0.0, 0.0}; 1335 PetscBool isLabeled = PETSC_FALSE; 1336 PetscScalar *cellCoords = NULL; 1337 const PetscScalar *array; 1338 PetscInt numCoords, cdim, d; 1339 PetscBool isDG; 1340 1341 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1342 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1343 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1344 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1345 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1346 for (p = 0; p < numCoords / cdim; ++p) { 1347 for (d = 0; d < cdim; ++d) { 1348 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1349 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1350 } 1351 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1352 if (cdim == 3) { 1353 PetscReal tmp = tcoords[1]; 1354 tcoords[1] = tcoords[2]; 1355 tcoords[2] = -tmp; 1356 } 1357 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1358 } 1359 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1360 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1361 for (d = 0; d < cdim; ++d) { 1362 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1363 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1364 } 1365 if (drawHasse) color = colors[depth % numColors]; 1366 else color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 isLabeled = PETSC_TRUE; 1373 break; 1374 } 1375 } 1376 if (drawNumbers[dim]) { 1377 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1378 } else if (drawColors[dim]) { 1379 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1380 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1381 } 1382 if (drawHasse) { 1383 color = colors[depth % numColors]; 1384 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1388 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1389 1390 color = colors[1 % numColors]; 1391 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1396 1397 color = colors[0 % numColors]; 1398 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1403 1404 for (p = pStart; p < pEnd; ++p) { 1405 const PetscInt *cone; 1406 PetscInt coneSize, cp; 1407 1408 PetscCall(DMPlexGetCone(dm, p, &cone)); 1409 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1410 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1411 } 1412 } 1413 PetscCall(PetscViewerFlush(viewer)); 1414 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1417 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1418 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1419 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1420 PetscCall(PetscFree3(names, colors, lcolors)); 1421 PetscCall(PetscBTDestroy(&wp)); 1422 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1423 Vec cown, acown; 1424 VecScatter sct; 1425 ISLocalToGlobalMapping g2l; 1426 IS gid, acis; 1427 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1428 MPI_Group ggroup, ngroup; 1429 PetscScalar *array, nid; 1430 const PetscInt *idxs; 1431 PetscInt *idxs2, *start, *adjacency, *work; 1432 PetscInt64 lm[3], gm[3]; 1433 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1434 PetscMPIInt d1, d2, rank; 1435 1436 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1437 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1438 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1439 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1440 #endif 1441 if (ncomm != MPI_COMM_NULL) { 1442 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1443 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1444 d1 = 0; 1445 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1446 nid = d2; 1447 PetscCallMPI(MPI_Group_free(&ggroup)); 1448 PetscCallMPI(MPI_Group_free(&ngroup)); 1449 PetscCallMPI(MPI_Comm_free(&ncomm)); 1450 } else nid = 0.0; 1451 1452 /* Get connectivity */ 1453 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1454 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1455 1456 /* filter overlapped local cells */ 1457 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1458 PetscCall(ISGetIndices(gid, &idxs)); 1459 PetscCall(ISGetLocalSize(gid, &cum)); 1460 PetscCall(PetscMalloc1(cum, &idxs2)); 1461 for (c = cStart, cum = 0; c < cEnd; c++) { 1462 if (idxs[c - cStart] < 0) continue; 1463 idxs2[cum++] = idxs[c - cStart]; 1464 } 1465 PetscCall(ISRestoreIndices(gid, &idxs)); 1466 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1467 PetscCall(ISDestroy(&gid)); 1468 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1469 1470 /* support for node-aware cell locality */ 1471 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1472 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1473 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1474 PetscCall(VecGetArray(cown, &array)); 1475 for (c = 0; c < numVertices; c++) array[c] = nid; 1476 PetscCall(VecRestoreArray(cown, &array)); 1477 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1478 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1479 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1480 PetscCall(ISDestroy(&acis)); 1481 PetscCall(VecScatterDestroy(&sct)); 1482 PetscCall(VecDestroy(&cown)); 1483 1484 /* compute edgeCut */ 1485 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1486 PetscCall(PetscMalloc1(cum, &work)); 1487 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1488 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1489 PetscCall(ISDestroy(&gid)); 1490 PetscCall(VecGetArray(acown, &array)); 1491 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1492 PetscInt totl; 1493 1494 totl = start[c + 1] - start[c]; 1495 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1496 for (i = 0; i < totl; i++) { 1497 if (work[i] < 0) { 1498 ect += 1; 1499 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1500 } 1501 } 1502 } 1503 PetscCall(PetscFree(work)); 1504 PetscCall(VecRestoreArray(acown, &array)); 1505 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1506 lm[1] = -numVertices; 1507 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1509 lm[0] = ect; /* edgeCut */ 1510 lm[1] = ectn; /* node-aware edgeCut */ 1511 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1512 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1513 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1514 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1515 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1516 #else 1517 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1518 #endif 1519 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1520 PetscCall(PetscFree(start)); 1521 PetscCall(PetscFree(adjacency)); 1522 PetscCall(VecDestroy(&acown)); 1523 } else { 1524 const char *name; 1525 PetscInt *sizes, *hybsizes, *ghostsizes; 1526 PetscInt locDepth, depth, cellHeight, dim, d; 1527 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1528 PetscInt numLabels, l, maxSize = 17; 1529 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1530 MPI_Comm comm; 1531 PetscMPIInt size, rank; 1532 1533 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1534 PetscCallMPI(MPI_Comm_size(comm, &size)); 1535 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1536 PetscCall(DMGetDimension(dm, &dim)); 1537 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1538 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1539 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1540 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1541 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1542 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1543 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1544 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1545 gcNum = gcEnd - gcStart; 1546 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1547 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1548 for (d = 0; d <= depth; d++) { 1549 PetscInt Nc[2] = {0, 0}, ict; 1550 1551 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1552 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1553 ict = ct0; 1554 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1555 ct0 = (DMPolytopeType)ict; 1556 for (p = pStart; p < pEnd; ++p) { 1557 DMPolytopeType ct; 1558 1559 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1560 if (ct == ct0) ++Nc[0]; 1561 else ++Nc[1]; 1562 } 1563 if (size < maxSize) { 1564 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1565 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1566 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1567 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1568 for (p = 0; p < size; ++p) { 1569 if (rank == 0) { 1570 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1571 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1572 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1573 } 1574 } 1575 } else { 1576 PetscInt locMinMax[2]; 1577 1578 locMinMax[0] = Nc[0] + Nc[1]; 1579 locMinMax[1] = Nc[0] + Nc[1]; 1580 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1581 locMinMax[0] = Nc[1]; 1582 locMinMax[1] = Nc[1]; 1583 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1584 if (d == depth) { 1585 locMinMax[0] = gcNum; 1586 locMinMax[1] = gcNum; 1587 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1588 } 1589 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1590 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1591 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1592 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1593 } 1594 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1595 } 1596 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1597 { 1598 const PetscReal *maxCell; 1599 const PetscReal *L; 1600 PetscBool localized; 1601 1602 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1603 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1604 if (L || localized) { 1605 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1606 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1607 if (L) { 1608 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1609 for (d = 0; d < dim; ++d) { 1610 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1611 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1612 } 1613 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1614 } 1615 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1616 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1617 } 1618 } 1619 PetscCall(DMGetNumLabels(dm, &numLabels)); 1620 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1621 for (l = 0; l < numLabels; ++l) { 1622 DMLabel label; 1623 const char *name; 1624 IS valueIS; 1625 const PetscInt *values; 1626 PetscInt numValues, v; 1627 1628 PetscCall(DMGetLabelName(dm, l, &name)); 1629 PetscCall(DMGetLabel(dm, name, &label)); 1630 PetscCall(DMLabelGetNumValues(label, &numValues)); 1631 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1632 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1633 PetscCall(ISGetIndices(valueIS, &values)); 1634 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1635 for (v = 0; v < numValues; ++v) { 1636 PetscInt size; 1637 1638 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1639 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1640 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1641 } 1642 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1643 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1644 PetscCall(ISRestoreIndices(valueIS, &values)); 1645 PetscCall(ISDestroy(&valueIS)); 1646 } 1647 { 1648 char **labelNames; 1649 PetscInt Nl = numLabels; 1650 PetscBool flg; 1651 1652 PetscCall(PetscMalloc1(Nl, &labelNames)); 1653 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1654 for (l = 0; l < Nl; ++l) { 1655 DMLabel label; 1656 1657 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1658 if (flg) { 1659 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1660 PetscCall(DMLabelView(label, viewer)); 1661 } 1662 PetscCall(PetscFree(labelNames[l])); 1663 } 1664 PetscCall(PetscFree(labelNames)); 1665 } 1666 /* If no fields are specified, people do not want to see adjacency */ 1667 if (dm->Nf) { 1668 PetscInt f; 1669 1670 for (f = 0; f < dm->Nf; ++f) { 1671 const char *name; 1672 1673 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1674 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1675 PetscCall(PetscViewerASCIIPushTab(viewer)); 1676 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1677 if (dm->fields[f].adjacency[0]) { 1678 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1679 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1680 } else { 1681 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1682 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1683 } 1684 PetscCall(PetscViewerASCIIPopTab(viewer)); 1685 } 1686 } 1687 PetscCall(DMGetCoarseDM(dm, &cdm)); 1688 if (cdm) { 1689 PetscCall(PetscViewerASCIIPushTab(viewer)); 1690 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1691 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1692 PetscCall(PetscViewerASCIIPopTab(viewer)); 1693 } 1694 } 1695 PetscFunctionReturn(PETSC_SUCCESS); 1696 } 1697 1698 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1699 { 1700 DMPolytopeType ct; 1701 PetscMPIInt rank; 1702 PetscInt cdim; 1703 1704 PetscFunctionBegin; 1705 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1706 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1707 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1708 switch (ct) { 1709 case DM_POLYTOPE_SEGMENT: 1710 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1711 switch (cdim) { 1712 case 1: { 1713 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1714 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1715 1716 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1718 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1719 } break; 1720 case 2: { 1721 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1722 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1723 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1724 1725 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1726 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)); 1727 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)); 1728 } break; 1729 default: 1730 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1731 } 1732 break; 1733 case DM_POLYTOPE_TRIANGLE: 1734 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)); 1735 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1738 break; 1739 case DM_POLYTOPE_QUADRILATERAL: 1740 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)); 1741 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)); 1742 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1746 break; 1747 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1748 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)); 1749 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)); 1750 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1754 break; 1755 case DM_POLYTOPE_FV_GHOST: 1756 break; 1757 default: 1758 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1759 } 1760 PetscFunctionReturn(PETSC_SUCCESS); 1761 } 1762 1763 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1764 { 1765 DMPolytopeType ct; 1766 PetscReal centroid[2] = {0., 0.}; 1767 PetscMPIInt rank; 1768 PetscInt fillColor, v, e, d; 1769 1770 PetscFunctionBegin; 1771 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1772 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1773 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1774 switch (ct) { 1775 case DM_POLYTOPE_TRIANGLE: { 1776 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1777 1778 for (v = 0; v < 3; ++v) { 1779 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1780 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1781 } 1782 for (e = 0; e < 3; ++e) { 1783 refCoords[0] = refVertices[e * 2 + 0]; 1784 refCoords[1] = refVertices[e * 2 + 1]; 1785 for (d = 1; d <= edgeDiv; ++d) { 1786 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1787 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1788 } 1789 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1790 for (d = 0; d < edgeDiv; ++d) { 1791 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)); 1792 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1793 } 1794 } 1795 } break; 1796 default: 1797 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1798 } 1799 PetscFunctionReturn(PETSC_SUCCESS); 1800 } 1801 1802 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1803 { 1804 PetscDraw draw; 1805 DM cdm; 1806 PetscSection coordSection; 1807 Vec coordinates; 1808 PetscReal xyl[3], xyr[3]; 1809 PetscReal *refCoords, *edgeCoords; 1810 PetscBool isnull, drawAffine = PETSC_TRUE; 1811 PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4; 1812 1813 PetscFunctionBegin; 1814 PetscCall(DMGetCoordinateDim(dm, &dim)); 1815 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1816 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1817 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1818 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1819 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1820 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1821 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1822 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1823 1824 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1825 PetscCall(PetscDrawIsNull(draw, &isnull)); 1826 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1827 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1828 1829 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1830 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1831 PetscCall(PetscDrawClear(draw)); 1832 1833 for (c = cStart; c < cEnd; ++c) { 1834 PetscScalar *coords = NULL; 1835 const PetscScalar *coords_arr; 1836 PetscInt numCoords; 1837 PetscBool isDG; 1838 1839 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1840 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1841 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1842 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1843 } 1844 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1845 PetscCall(PetscDrawFlush(draw)); 1846 PetscCall(PetscDrawPause(draw)); 1847 PetscCall(PetscDrawSave(draw)); 1848 PetscFunctionReturn(PETSC_SUCCESS); 1849 } 1850 1851 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1852 { 1853 DM odm = dm, rdm = dm, cdm; 1854 PetscFE fe; 1855 PetscSpace sp; 1856 PetscClassId id; 1857 PetscInt degree; 1858 PetscBool hoView = PETSC_TRUE; 1859 1860 PetscFunctionBegin; 1861 PetscObjectOptionsBegin((PetscObject)dm); 1862 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1863 PetscOptionsEnd(); 1864 PetscCall(PetscObjectReference((PetscObject)dm)); 1865 *hdm = dm; 1866 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1867 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1868 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1869 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1870 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1871 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1872 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1873 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1874 DM cdm, rcdm; 1875 Mat In; 1876 Vec cl, rcl; 1877 1878 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1879 if (rd > 1) PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1880 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1881 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1882 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1883 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1884 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1885 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1886 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1887 PetscCall(MatMult(In, cl, rcl)); 1888 PetscCall(MatDestroy(&In)); 1889 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1890 PetscCall(DMDestroy(&odm)); 1891 odm = rdm; 1892 } 1893 *hdm = rdm; 1894 PetscFunctionReturn(PETSC_SUCCESS); 1895 } 1896 1897 #if defined(PETSC_HAVE_EXODUSII) 1898 #include <exodusII.h> 1899 #include <petscviewerexodusii.h> 1900 #endif 1901 1902 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1903 { 1904 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1905 char name[PETSC_MAX_PATH_LEN]; 1906 1907 PetscFunctionBegin; 1908 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1909 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1910 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1911 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1912 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1913 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1914 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1916 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1917 if (iascii) { 1918 PetscViewerFormat format; 1919 PetscCall(PetscViewerGetFormat(viewer, &format)); 1920 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1921 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1922 } else if (ishdf5) { 1923 #if defined(PETSC_HAVE_HDF5) 1924 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1925 #else 1926 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1927 #endif 1928 } else if (isvtk) { 1929 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1930 } else if (isdraw) { 1931 DM hdm; 1932 1933 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1934 PetscCall(DMPlexView_Draw(hdm, viewer)); 1935 PetscCall(DMDestroy(&hdm)); 1936 } else if (isglvis) { 1937 PetscCall(DMPlexView_GLVis(dm, viewer)); 1938 #if defined(PETSC_HAVE_EXODUSII) 1939 } else if (isexodus) { 1940 /* 1941 exodusII requires that all sets be part of exactly one cell set. 1942 If the dm does not have a "Cell Sets" label defined, we create one 1943 with ID 1, containing all cells. 1944 Note that if the Cell Sets label is defined but does not cover all cells, 1945 we may still have a problem. This should probably be checked here or in the viewer; 1946 */ 1947 PetscInt numCS; 1948 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1949 if (!numCS) { 1950 PetscInt cStart, cEnd, c; 1951 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1952 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1953 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1954 } 1955 PetscCall(DMView_PlexExodusII(dm, viewer)); 1956 #endif 1957 #if defined(PETSC_HAVE_CGNS) 1958 } else if (iscgns) { 1959 PetscCall(DMView_PlexCGNS(dm, viewer)); 1960 #endif 1961 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1962 /* Optionally view the partition */ 1963 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1964 if (flg) { 1965 Vec ranks; 1966 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1967 PetscCall(VecView(ranks, viewer)); 1968 PetscCall(VecDestroy(&ranks)); 1969 } 1970 /* Optionally view a label */ 1971 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1972 if (flg) { 1973 DMLabel label; 1974 Vec val; 1975 1976 PetscCall(DMGetLabel(dm, name, &label)); 1977 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1978 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1979 PetscCall(VecView(val, viewer)); 1980 PetscCall(VecDestroy(&val)); 1981 } 1982 PetscFunctionReturn(PETSC_SUCCESS); 1983 } 1984 1985 /*@ 1986 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1987 1988 Collective 1989 1990 Input Parameters: 1991 + dm - The `DM` whose topology is to be saved 1992 - viewer - The `PetscViewer` to save it in 1993 1994 Level: advanced 1995 1996 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1997 @*/ 1998 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1999 { 2000 PetscBool ishdf5; 2001 2002 PetscFunctionBegin; 2003 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2004 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2005 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2006 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2007 if (ishdf5) { 2008 #if defined(PETSC_HAVE_HDF5) 2009 PetscViewerFormat format; 2010 PetscCall(PetscViewerGetFormat(viewer, &format)); 2011 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2012 IS globalPointNumbering; 2013 2014 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2015 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2016 PetscCall(ISDestroy(&globalPointNumbering)); 2017 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2018 #else 2019 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2020 #endif 2021 } 2022 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2023 PetscFunctionReturn(PETSC_SUCCESS); 2024 } 2025 2026 /*@ 2027 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2028 2029 Collective 2030 2031 Input Parameters: 2032 + dm - The `DM` whose coordinates are to be saved 2033 - viewer - The `PetscViewer` for saving 2034 2035 Level: advanced 2036 2037 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2038 @*/ 2039 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2040 { 2041 PetscBool ishdf5; 2042 2043 PetscFunctionBegin; 2044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2045 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2046 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2047 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2048 if (ishdf5) { 2049 #if defined(PETSC_HAVE_HDF5) 2050 PetscViewerFormat format; 2051 PetscCall(PetscViewerGetFormat(viewer, &format)); 2052 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2053 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2054 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2055 #else 2056 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2057 #endif 2058 } 2059 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2060 PetscFunctionReturn(PETSC_SUCCESS); 2061 } 2062 2063 /*@ 2064 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2065 2066 Collective 2067 2068 Input Parameters: 2069 + dm - The `DM` whose labels are to be saved 2070 - viewer - The `PetscViewer` for saving 2071 2072 Level: advanced 2073 2074 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2075 @*/ 2076 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2077 { 2078 PetscBool ishdf5; 2079 2080 PetscFunctionBegin; 2081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2082 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2083 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2084 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2085 if (ishdf5) { 2086 #if defined(PETSC_HAVE_HDF5) 2087 IS globalPointNumbering; 2088 PetscViewerFormat format; 2089 2090 PetscCall(PetscViewerGetFormat(viewer, &format)); 2091 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2092 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2093 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2094 PetscCall(ISDestroy(&globalPointNumbering)); 2095 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2096 #else 2097 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2098 #endif 2099 } 2100 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2101 PetscFunctionReturn(PETSC_SUCCESS); 2102 } 2103 2104 /*@ 2105 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2106 2107 Collective 2108 2109 Input Parameters: 2110 + dm - The `DM` that contains the topology on which the section to be saved is defined 2111 . viewer - The `PetscViewer` for saving 2112 - sectiondm - The `DM` that contains the section to be saved 2113 2114 Level: advanced 2115 2116 Notes: 2117 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. 2118 2119 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 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. 2120 2121 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2122 @*/ 2123 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2124 { 2125 PetscBool ishdf5; 2126 2127 PetscFunctionBegin; 2128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2129 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2130 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2131 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2132 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2133 if (ishdf5) { 2134 #if defined(PETSC_HAVE_HDF5) 2135 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2136 #else 2137 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2138 #endif 2139 } 2140 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2141 PetscFunctionReturn(PETSC_SUCCESS); 2142 } 2143 2144 /*@ 2145 DMPlexGlobalVectorView - Saves a global vector 2146 2147 Collective 2148 2149 Input Parameters: 2150 + dm - The `DM` that represents the topology 2151 . viewer - The `PetscViewer` to save data with 2152 . sectiondm - The `DM` that contains the global section on which vec is defined 2153 - vec - The global vector to be saved 2154 2155 Level: advanced 2156 2157 Notes: 2158 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 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. 2159 2160 Calling sequence: 2161 .vb 2162 DMCreate(PETSC_COMM_WORLD, &dm); 2163 DMSetType(dm, DMPLEX); 2164 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2165 DMClone(dm, §iondm); 2166 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2167 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2168 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2169 PetscSectionSetChart(section, pStart, pEnd); 2170 PetscSectionSetUp(section); 2171 DMSetLocalSection(sectiondm, section); 2172 PetscSectionDestroy(§ion); 2173 DMGetGlobalVector(sectiondm, &vec); 2174 PetscObjectSetName((PetscObject)vec, "vec_name"); 2175 DMPlexTopologyView(dm, viewer); 2176 DMPlexSectionView(dm, viewer, sectiondm); 2177 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2178 DMRestoreGlobalVector(sectiondm, &vec); 2179 DMDestroy(§iondm); 2180 DMDestroy(&dm); 2181 .ve 2182 2183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2184 @*/ 2185 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2186 { 2187 PetscBool ishdf5; 2188 2189 PetscFunctionBegin; 2190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2191 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2192 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2193 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2194 /* Check consistency */ 2195 { 2196 PetscSection section; 2197 PetscBool includesConstraints; 2198 PetscInt m, m1; 2199 2200 PetscCall(VecGetLocalSize(vec, &m1)); 2201 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2202 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2203 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2204 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2205 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2206 } 2207 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2208 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2209 if (ishdf5) { 2210 #if defined(PETSC_HAVE_HDF5) 2211 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 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_GlobalVectorView, viewer, 0, 0, 0)); 2217 PetscFunctionReturn(PETSC_SUCCESS); 2218 } 2219 2220 /*@ 2221 DMPlexLocalVectorView - Saves a local vector 2222 2223 Collective 2224 2225 Input Parameters: 2226 + dm - The `DM` that represents the topology 2227 . viewer - The `PetscViewer` to save data with 2228 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2229 - vec - The local vector to be saved 2230 2231 Level: advanced 2232 2233 Note: 2234 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 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. 2235 2236 Calling sequence: 2237 .vb 2238 DMCreate(PETSC_COMM_WORLD, &dm); 2239 DMSetType(dm, DMPLEX); 2240 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2241 DMClone(dm, §iondm); 2242 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2243 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2244 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2245 PetscSectionSetChart(section, pStart, pEnd); 2246 PetscSectionSetUp(section); 2247 DMSetLocalSection(sectiondm, section); 2248 DMGetLocalVector(sectiondm, &vec); 2249 PetscObjectSetName((PetscObject)vec, "vec_name"); 2250 DMPlexTopologyView(dm, viewer); 2251 DMPlexSectionView(dm, viewer, sectiondm); 2252 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2253 DMRestoreLocalVector(sectiondm, &vec); 2254 DMDestroy(§iondm); 2255 DMDestroy(&dm); 2256 .ve 2257 2258 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2259 @*/ 2260 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2261 { 2262 PetscBool ishdf5; 2263 2264 PetscFunctionBegin; 2265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2266 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2267 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2268 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2269 /* Check consistency */ 2270 { 2271 PetscSection section; 2272 PetscBool includesConstraints; 2273 PetscInt m, m1; 2274 2275 PetscCall(VecGetLocalSize(vec, &m1)); 2276 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2277 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2278 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2279 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2280 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2281 } 2282 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2283 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2284 if (ishdf5) { 2285 #if defined(PETSC_HAVE_HDF5) 2286 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2287 #else 2288 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2289 #endif 2290 } 2291 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2292 PetscFunctionReturn(PETSC_SUCCESS); 2293 } 2294 2295 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2296 { 2297 PetscBool ishdf5; 2298 2299 PetscFunctionBegin; 2300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2301 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2302 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2303 if (ishdf5) { 2304 #if defined(PETSC_HAVE_HDF5) 2305 PetscViewerFormat format; 2306 PetscCall(PetscViewerGetFormat(viewer, &format)); 2307 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2308 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2309 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2310 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2311 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2312 PetscFunctionReturn(PETSC_SUCCESS); 2313 #else 2314 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2315 #endif 2316 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2317 } 2318 2319 /*@ 2320 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2321 2322 Collective 2323 2324 Input Parameters: 2325 + dm - The `DM` into which the topology is loaded 2326 - viewer - The `PetscViewer` for the saved topology 2327 2328 Output Parameter: 2329 . 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; `NULL` if unneeded 2330 2331 Level: advanced 2332 2333 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2334 `PetscViewer`, `PetscSF` 2335 @*/ 2336 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2337 { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2344 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2345 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2346 if (ishdf5) { 2347 #if defined(PETSC_HAVE_HDF5) 2348 PetscViewerFormat format; 2349 PetscCall(PetscViewerGetFormat(viewer, &format)); 2350 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2351 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2352 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2353 #else 2354 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2355 #endif 2356 } 2357 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2358 PetscFunctionReturn(PETSC_SUCCESS); 2359 } 2360 2361 /*@ 2362 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2363 2364 Collective 2365 2366 Input Parameters: 2367 + dm - The `DM` into which the coordinates are loaded 2368 . viewer - The `PetscViewer` for the saved coordinates 2369 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2370 2371 Level: advanced 2372 2373 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2374 `PetscSF`, `PetscViewer` 2375 @*/ 2376 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2377 { 2378 PetscBool ishdf5; 2379 2380 PetscFunctionBegin; 2381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2382 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2383 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2384 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2385 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2386 if (ishdf5) { 2387 #if defined(PETSC_HAVE_HDF5) 2388 PetscViewerFormat format; 2389 PetscCall(PetscViewerGetFormat(viewer, &format)); 2390 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2391 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2392 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2393 #else 2394 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2395 #endif 2396 } 2397 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2398 PetscFunctionReturn(PETSC_SUCCESS); 2399 } 2400 2401 /*@ 2402 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2403 2404 Collective 2405 2406 Input Parameters: 2407 + dm - The `DM` into which the labels are loaded 2408 . viewer - The `PetscViewer` for the saved labels 2409 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2410 2411 Level: advanced 2412 2413 Note: 2414 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2415 2416 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2417 `PetscSF`, `PetscViewer` 2418 @*/ 2419 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2420 { 2421 PetscBool ishdf5; 2422 2423 PetscFunctionBegin; 2424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2425 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2426 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2427 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2428 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2429 if (ishdf5) { 2430 #if defined(PETSC_HAVE_HDF5) 2431 PetscViewerFormat format; 2432 2433 PetscCall(PetscViewerGetFormat(viewer, &format)); 2434 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2435 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2436 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2437 #else 2438 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2439 #endif 2440 } 2441 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2442 PetscFunctionReturn(PETSC_SUCCESS); 2443 } 2444 2445 /*@ 2446 DMPlexSectionLoad - Loads section into a `DMPLEX` 2447 2448 Collective 2449 2450 Input Parameters: 2451 + dm - The `DM` that represents the topology 2452 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2453 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2454 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2455 2456 Output Parameters: 2457 + 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) 2458 - 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) 2459 2460 Level: advanced 2461 2462 Notes: 2463 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. 2464 2465 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 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. 2466 2467 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. 2468 2469 Example using 2 processes: 2470 .vb 2471 NX (number of points on dm): 4 2472 sectionA : the on-disk section 2473 vecA : a vector associated with sectionA 2474 sectionB : sectiondm's local section constructed in this function 2475 vecB (local) : a vector associated with sectiondm's local section 2476 vecB (global) : a vector associated with sectiondm's global section 2477 2478 rank 0 rank 1 2479 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2480 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2481 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2482 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2483 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2484 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2485 sectionB->atlasDof : 1 0 1 | 1 3 2486 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2487 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2488 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2489 .ve 2490 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2491 2492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2493 @*/ 2494 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2495 { 2496 PetscBool ishdf5; 2497 2498 PetscFunctionBegin; 2499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2500 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2501 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2502 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2503 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2504 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2505 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2506 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2507 if (ishdf5) { 2508 #if defined(PETSC_HAVE_HDF5) 2509 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2510 #else 2511 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2512 #endif 2513 } 2514 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2515 PetscFunctionReturn(PETSC_SUCCESS); 2516 } 2517 2518 /*@ 2519 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2520 2521 Collective 2522 2523 Input Parameters: 2524 + dm - The `DM` that represents the topology 2525 . viewer - The `PetscViewer` that represents the on-disk vector data 2526 . sectiondm - The `DM` that contains the global section on which vec is defined 2527 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2528 - vec - The global vector to set values of 2529 2530 Level: advanced 2531 2532 Notes: 2533 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 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. 2534 2535 Calling sequence: 2536 .vb 2537 DMCreate(PETSC_COMM_WORLD, &dm); 2538 DMSetType(dm, DMPLEX); 2539 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2540 DMPlexTopologyLoad(dm, viewer, &sfX); 2541 DMClone(dm, §iondm); 2542 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2543 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2544 DMGetGlobalVector(sectiondm, &vec); 2545 PetscObjectSetName((PetscObject)vec, "vec_name"); 2546 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2547 DMRestoreGlobalVector(sectiondm, &vec); 2548 PetscSFDestroy(&gsf); 2549 PetscSFDestroy(&sfX); 2550 DMDestroy(§iondm); 2551 DMDestroy(&dm); 2552 .ve 2553 2554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2555 `PetscSF`, `PetscViewer` 2556 @*/ 2557 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2558 { 2559 PetscBool ishdf5; 2560 2561 PetscFunctionBegin; 2562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2563 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2564 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2565 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2566 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2567 /* Check consistency */ 2568 { 2569 PetscSection section; 2570 PetscBool includesConstraints; 2571 PetscInt m, m1; 2572 2573 PetscCall(VecGetLocalSize(vec, &m1)); 2574 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2575 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2576 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2577 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2578 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2579 } 2580 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2581 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2582 if (ishdf5) { 2583 #if defined(PETSC_HAVE_HDF5) 2584 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2585 #else 2586 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2587 #endif 2588 } 2589 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2590 PetscFunctionReturn(PETSC_SUCCESS); 2591 } 2592 2593 /*@ 2594 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2595 2596 Collective 2597 2598 Input Parameters: 2599 + dm - The `DM` that represents the topology 2600 . viewer - The `PetscViewer` that represents the on-disk vector data 2601 . sectiondm - The `DM` that contains the local section on which vec is defined 2602 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2603 - vec - The local vector to set values of 2604 2605 Level: advanced 2606 2607 Notes: 2608 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 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. 2609 2610 Calling sequence: 2611 .vb 2612 DMCreate(PETSC_COMM_WORLD, &dm); 2613 DMSetType(dm, DMPLEX); 2614 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2615 DMPlexTopologyLoad(dm, viewer, &sfX); 2616 DMClone(dm, §iondm); 2617 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2618 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2619 DMGetLocalVector(sectiondm, &vec); 2620 PetscObjectSetName((PetscObject)vec, "vec_name"); 2621 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2622 DMRestoreLocalVector(sectiondm, &vec); 2623 PetscSFDestroy(&lsf); 2624 PetscSFDestroy(&sfX); 2625 DMDestroy(§iondm); 2626 DMDestroy(&dm); 2627 .ve 2628 2629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2630 `PetscSF`, `PetscViewer` 2631 @*/ 2632 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2633 { 2634 PetscBool ishdf5; 2635 2636 PetscFunctionBegin; 2637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2638 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2639 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2640 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2641 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2642 /* Check consistency */ 2643 { 2644 PetscSection section; 2645 PetscBool includesConstraints; 2646 PetscInt m, m1; 2647 2648 PetscCall(VecGetLocalSize(vec, &m1)); 2649 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2650 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2651 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2652 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2653 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2654 } 2655 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2656 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2657 if (ishdf5) { 2658 #if defined(PETSC_HAVE_HDF5) 2659 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2660 #else 2661 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2662 #endif 2663 } 2664 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2665 PetscFunctionReturn(PETSC_SUCCESS); 2666 } 2667 2668 PetscErrorCode DMDestroy_Plex(DM dm) 2669 { 2670 DM_Plex *mesh = (DM_Plex *)dm->data; 2671 2672 PetscFunctionBegin; 2673 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2674 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2675 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2676 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2677 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2678 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2679 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2680 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2681 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2682 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2683 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2684 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2685 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2686 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2687 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2688 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2689 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2690 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2691 PetscCall(PetscFree(mesh->cones)); 2692 PetscCall(PetscFree(mesh->coneOrientations)); 2693 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2694 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2695 PetscCall(PetscFree(mesh->supports)); 2696 PetscCall(PetscFree(mesh->cellTypes)); 2697 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2698 PetscCall(PetscFree(mesh->tetgenOpts)); 2699 PetscCall(PetscFree(mesh->triangleOpts)); 2700 PetscCall(PetscFree(mesh->transformType)); 2701 PetscCall(PetscFree(mesh->distributionName)); 2702 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2703 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2704 PetscCall(ISDestroy(&mesh->subpointIS)); 2705 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2706 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2707 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2708 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2709 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2710 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2711 PetscCall(ISDestroy(&mesh->anchorIS)); 2712 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2713 PetscCall(PetscFree(mesh->parents)); 2714 PetscCall(PetscFree(mesh->childIDs)); 2715 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2716 PetscCall(PetscFree(mesh->children)); 2717 PetscCall(DMDestroy(&mesh->referenceTree)); 2718 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2719 PetscCall(PetscFree(mesh->neighbors)); 2720 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2721 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2722 PetscCall(PetscFree(mesh)); 2723 PetscFunctionReturn(PETSC_SUCCESS); 2724 } 2725 2726 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2727 { 2728 PetscSection sectionGlobal; 2729 PetscInt bs = -1, mbs; 2730 PetscInt localSize, localStart = 0; 2731 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2732 MatType mtype; 2733 ISLocalToGlobalMapping ltog; 2734 2735 PetscFunctionBegin; 2736 PetscCall(MatInitializePackage()); 2737 mtype = dm->mattype; 2738 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2739 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2740 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2741 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2742 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2743 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2744 PetscCall(MatSetType(*J, mtype)); 2745 PetscCall(MatSetFromOptions(*J)); 2746 PetscCall(MatGetBlockSize(*J, &mbs)); 2747 if (mbs > 1) bs = mbs; 2748 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2749 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2750 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2751 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2752 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2753 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2754 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2755 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2756 if (!isShell) { 2757 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2758 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2759 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2760 2761 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2762 2763 PetscCall(PetscCalloc1(localSize, &pblocks)); 2764 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2765 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2766 for (p = pStart; p < pEnd; ++p) { 2767 switch (dm->blocking_type) { 2768 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2769 PetscInt bdof, offset; 2770 2771 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2772 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2773 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2774 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2775 dof = dof < 0 ? -(dof + 1) : dof; 2776 bdof = cdof && (dof - cdof) ? 1 : dof; 2777 if (dof) { 2778 if (bs < 0) { 2779 bs = bdof; 2780 } else if (bs != bdof) { 2781 bs = 1; 2782 } 2783 } 2784 } break; 2785 case DM_BLOCKING_FIELD_NODE: { 2786 for (PetscInt field = 0; field < num_fields; field++) { 2787 PetscInt num_comp, bdof, offset; 2788 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2789 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2790 if (dof < 0) continue; 2791 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2792 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2793 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); 2794 PetscInt num_nodes = dof / num_comp; 2795 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2796 // Handle possibly constant block size (unlikely) 2797 bdof = cdof && (dof - cdof) ? 1 : dof; 2798 if (dof) { 2799 if (bs < 0) { 2800 bs = bdof; 2801 } else if (bs != bdof) { 2802 bs = 1; 2803 } 2804 } 2805 } 2806 } break; 2807 } 2808 } 2809 /* Must have same blocksize on all procs (some might have no points) */ 2810 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2811 bsLocal[1] = bs; 2812 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2813 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2814 else bs = bsMinMax[0]; 2815 bs = PetscMax(1, bs); 2816 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2817 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2818 PetscCall(MatSetBlockSize(*J, bs)); 2819 PetscCall(MatSetUp(*J)); 2820 } else { 2821 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2822 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2823 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2824 } 2825 { // Consolidate blocks 2826 PetscInt nblocks = 0; 2827 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2828 if (pblocks[i] == 0) continue; 2829 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2830 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2831 } 2832 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2833 } 2834 PetscCall(PetscFree(pblocks)); 2835 } 2836 PetscCall(MatSetDM(*J, dm)); 2837 PetscFunctionReturn(PETSC_SUCCESS); 2838 } 2839 2840 /*@ 2841 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2842 2843 Not Collective 2844 2845 Input Parameter: 2846 . dm - The `DMPLEX` 2847 2848 Output Parameter: 2849 . subsection - The subdomain section 2850 2851 Level: developer 2852 2853 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2854 @*/ 2855 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2856 { 2857 DM_Plex *mesh = (DM_Plex *)dm->data; 2858 2859 PetscFunctionBegin; 2860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2861 if (!mesh->subdomainSection) { 2862 PetscSection section; 2863 PetscSF sf; 2864 2865 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2866 PetscCall(DMGetLocalSection(dm, §ion)); 2867 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2868 PetscCall(PetscSFDestroy(&sf)); 2869 } 2870 *subsection = mesh->subdomainSection; 2871 PetscFunctionReturn(PETSC_SUCCESS); 2872 } 2873 2874 /*@ 2875 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2876 2877 Not Collective 2878 2879 Input Parameter: 2880 . dm - The `DMPLEX` 2881 2882 Output Parameters: 2883 + pStart - The first mesh point 2884 - pEnd - The upper bound for mesh points 2885 2886 Level: beginner 2887 2888 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2889 @*/ 2890 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2891 { 2892 DM_Plex *mesh = (DM_Plex *)dm->data; 2893 2894 PetscFunctionBegin; 2895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2896 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2897 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2898 PetscFunctionReturn(PETSC_SUCCESS); 2899 } 2900 2901 /*@ 2902 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2903 2904 Not Collective 2905 2906 Input Parameters: 2907 + dm - The `DMPLEX` 2908 . pStart - The first mesh point 2909 - pEnd - The upper bound for mesh points 2910 2911 Level: beginner 2912 2913 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2914 @*/ 2915 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2916 { 2917 DM_Plex *mesh = (DM_Plex *)dm->data; 2918 2919 PetscFunctionBegin; 2920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2921 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2922 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2923 PetscCall(PetscFree(mesh->cellTypes)); 2924 PetscFunctionReturn(PETSC_SUCCESS); 2925 } 2926 2927 /*@ 2928 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2929 2930 Not Collective 2931 2932 Input Parameters: 2933 + dm - The `DMPLEX` 2934 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2935 2936 Output Parameter: 2937 . size - The cone size for point `p` 2938 2939 Level: beginner 2940 2941 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2942 @*/ 2943 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2944 { 2945 DM_Plex *mesh = (DM_Plex *)dm->data; 2946 2947 PetscFunctionBegin; 2948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2949 PetscAssertPointer(size, 3); 2950 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2951 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2952 PetscFunctionReturn(PETSC_SUCCESS); 2953 } 2954 2955 /*@ 2956 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2957 2958 Not Collective 2959 2960 Input Parameters: 2961 + dm - The `DMPLEX` 2962 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2963 - size - The cone size for point `p` 2964 2965 Level: beginner 2966 2967 Note: 2968 This should be called after `DMPlexSetChart()`. 2969 2970 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2971 @*/ 2972 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2973 { 2974 DM_Plex *mesh = (DM_Plex *)dm->data; 2975 2976 PetscFunctionBegin; 2977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2978 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2979 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2980 PetscFunctionReturn(PETSC_SUCCESS); 2981 } 2982 2983 /*@C 2984 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2985 2986 Not Collective 2987 2988 Input Parameters: 2989 + dm - The `DMPLEX` 2990 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2991 2992 Output Parameter: 2993 . cone - An array of points which are on the in-edges for point `p` 2994 2995 Level: beginner 2996 2997 Fortran Notes: 2998 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2999 `DMPlexRestoreCone()` is not needed/available in C. 3000 3001 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3002 @*/ 3003 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3004 { 3005 DM_Plex *mesh = (DM_Plex *)dm->data; 3006 PetscInt off; 3007 3008 PetscFunctionBegin; 3009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3010 PetscAssertPointer(cone, 3); 3011 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3012 *cone = &mesh->cones[off]; 3013 PetscFunctionReturn(PETSC_SUCCESS); 3014 } 3015 3016 /*@C 3017 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3018 3019 Not Collective 3020 3021 Input Parameters: 3022 + dm - The `DMPLEX` 3023 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3024 3025 Output Parameters: 3026 + pConesSection - `PetscSection` describing the layout of `pCones` 3027 - pCones - An array of points which are on the in-edges for the point set `p` 3028 3029 Level: intermediate 3030 3031 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3032 @*/ 3033 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3034 { 3035 PetscSection cs, newcs; 3036 PetscInt *cones; 3037 PetscInt *newarr = NULL; 3038 PetscInt n; 3039 3040 PetscFunctionBegin; 3041 PetscCall(DMPlexGetCones(dm, &cones)); 3042 PetscCall(DMPlexGetConeSection(dm, &cs)); 3043 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3044 if (pConesSection) *pConesSection = newcs; 3045 if (pCones) { 3046 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3047 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3048 } 3049 PetscFunctionReturn(PETSC_SUCCESS); 3050 } 3051 3052 /*@ 3053 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3054 3055 Not Collective 3056 3057 Input Parameters: 3058 + dm - The `DMPLEX` 3059 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3060 3061 Output Parameter: 3062 . expandedPoints - An array of vertices recursively expanded from input points 3063 3064 Level: advanced 3065 3066 Notes: 3067 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3068 3069 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3070 3071 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3072 `DMPlexGetDepth()`, `IS` 3073 @*/ 3074 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3075 { 3076 IS *expandedPointsAll; 3077 PetscInt depth; 3078 3079 PetscFunctionBegin; 3080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3081 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3082 PetscAssertPointer(expandedPoints, 3); 3083 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3084 *expandedPoints = expandedPointsAll[0]; 3085 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3086 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3087 PetscFunctionReturn(PETSC_SUCCESS); 3088 } 3089 3090 /*@ 3091 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 3092 3093 Not Collective 3094 3095 Input Parameters: 3096 + dm - The `DMPLEX` 3097 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3098 3099 Output Parameters: 3100 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3101 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3102 - sections - (optional) An array of sections which describe mappings from points to their cone points 3103 3104 Level: advanced 3105 3106 Notes: 3107 Like `DMPlexGetConeTuple()` but recursive. 3108 3109 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. 3110 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3111 3112 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\: 3113 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3114 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3115 3116 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3117 `DMPlexGetDepth()`, `PetscSection`, `IS` 3118 @*/ 3119 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3120 { 3121 const PetscInt *arr0 = NULL, *cone = NULL; 3122 PetscInt *arr = NULL, *newarr = NULL; 3123 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3124 IS *expandedPoints_; 3125 PetscSection *sections_; 3126 3127 PetscFunctionBegin; 3128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3129 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3130 if (depth) PetscAssertPointer(depth, 3); 3131 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3132 if (sections) PetscAssertPointer(sections, 5); 3133 PetscCall(ISGetLocalSize(points, &n)); 3134 PetscCall(ISGetIndices(points, &arr0)); 3135 PetscCall(DMPlexGetDepth(dm, &depth_)); 3136 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3137 PetscCall(PetscCalloc1(depth_, §ions_)); 3138 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3139 for (d = depth_ - 1; d >= 0; d--) { 3140 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3141 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3142 for (i = 0; i < n; i++) { 3143 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3144 if (arr[i] >= start && arr[i] < end) { 3145 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3146 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3147 } else { 3148 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3149 } 3150 } 3151 PetscCall(PetscSectionSetUp(sections_[d])); 3152 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3153 PetscCall(PetscMalloc1(newn, &newarr)); 3154 for (i = 0; i < n; i++) { 3155 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3156 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3157 if (cn > 1) { 3158 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3159 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3160 } else { 3161 newarr[co] = arr[i]; 3162 } 3163 } 3164 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3165 arr = newarr; 3166 n = newn; 3167 } 3168 PetscCall(ISRestoreIndices(points, &arr0)); 3169 *depth = depth_; 3170 if (expandedPoints) *expandedPoints = expandedPoints_; 3171 else { 3172 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3173 PetscCall(PetscFree(expandedPoints_)); 3174 } 3175 if (sections) *sections = sections_; 3176 else { 3177 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3178 PetscCall(PetscFree(sections_)); 3179 } 3180 PetscFunctionReturn(PETSC_SUCCESS); 3181 } 3182 3183 /*@ 3184 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3185 3186 Not Collective 3187 3188 Input Parameters: 3189 + dm - The `DMPLEX` 3190 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3191 3192 Output Parameters: 3193 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3194 . expandedPoints - (optional) An array of recursively expanded cones 3195 - sections - (optional) An array of sections which describe mappings from points to their cone points 3196 3197 Level: advanced 3198 3199 Note: 3200 See `DMPlexGetConeRecursive()` 3201 3202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3203 `DMPlexGetDepth()`, `IS`, `PetscSection` 3204 @*/ 3205 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3206 { 3207 PetscInt d, depth_; 3208 3209 PetscFunctionBegin; 3210 PetscCall(DMPlexGetDepth(dm, &depth_)); 3211 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3212 if (depth) *depth = 0; 3213 if (expandedPoints) { 3214 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3215 PetscCall(PetscFree(*expandedPoints)); 3216 } 3217 if (sections) { 3218 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3219 PetscCall(PetscFree(*sections)); 3220 } 3221 PetscFunctionReturn(PETSC_SUCCESS); 3222 } 3223 3224 /*@ 3225 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 3226 3227 Not Collective 3228 3229 Input Parameters: 3230 + dm - The `DMPLEX` 3231 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3232 - cone - An array of points which are on the in-edges for point `p` 3233 3234 Level: beginner 3235 3236 Note: 3237 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3238 3239 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3240 @*/ 3241 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3242 { 3243 DM_Plex *mesh = (DM_Plex *)dm->data; 3244 PetscInt dof, off, c; 3245 3246 PetscFunctionBegin; 3247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3248 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3249 if (dof) PetscAssertPointer(cone, 3); 3250 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3251 if (PetscDefined(USE_DEBUG)) { 3252 PetscInt pStart, pEnd; 3253 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3254 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); 3255 for (c = 0; c < dof; ++c) { 3256 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); 3257 mesh->cones[off + c] = cone[c]; 3258 } 3259 } else { 3260 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3261 } 3262 PetscFunctionReturn(PETSC_SUCCESS); 3263 } 3264 3265 /*@C 3266 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3267 3268 Not Collective 3269 3270 Input Parameters: 3271 + dm - The `DMPLEX` 3272 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3273 3274 Output Parameter: 3275 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3276 integer giving the prescription for cone traversal. 3277 3278 Level: beginner 3279 3280 Note: 3281 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3282 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3283 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3284 with the identity. 3285 3286 Fortran Notes: 3287 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3288 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3289 3290 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3291 @*/ 3292 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3293 { 3294 DM_Plex *mesh = (DM_Plex *)dm->data; 3295 PetscInt off; 3296 3297 PetscFunctionBegin; 3298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3299 if (PetscDefined(USE_DEBUG)) { 3300 PetscInt dof; 3301 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3302 if (dof) PetscAssertPointer(coneOrientation, 3); 3303 } 3304 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3305 3306 *coneOrientation = &mesh->coneOrientations[off]; 3307 PetscFunctionReturn(PETSC_SUCCESS); 3308 } 3309 3310 /*@ 3311 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3312 3313 Not Collective 3314 3315 Input Parameters: 3316 + dm - The `DMPLEX` 3317 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3318 - coneOrientation - An array of orientations 3319 3320 Level: beginner 3321 3322 Notes: 3323 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3324 3325 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3326 3327 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3328 @*/ 3329 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3330 { 3331 DM_Plex *mesh = (DM_Plex *)dm->data; 3332 PetscInt pStart, pEnd; 3333 PetscInt dof, off, c; 3334 3335 PetscFunctionBegin; 3336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3337 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3338 if (dof) PetscAssertPointer(coneOrientation, 3); 3339 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3340 if (PetscDefined(USE_DEBUG)) { 3341 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3342 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); 3343 for (c = 0; c < dof; ++c) { 3344 PetscInt cdof, o = coneOrientation[c]; 3345 3346 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3347 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); 3348 mesh->coneOrientations[off + c] = o; 3349 } 3350 } else { 3351 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3352 } 3353 PetscFunctionReturn(PETSC_SUCCESS); 3354 } 3355 3356 /*@ 3357 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3358 3359 Not Collective 3360 3361 Input Parameters: 3362 + dm - The `DMPLEX` 3363 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3364 . conePos - The local index in the cone where the point should be put 3365 - conePoint - The mesh point to insert 3366 3367 Level: beginner 3368 3369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3370 @*/ 3371 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3372 { 3373 DM_Plex *mesh = (DM_Plex *)dm->data; 3374 PetscInt pStart, pEnd; 3375 PetscInt dof, off; 3376 3377 PetscFunctionBegin; 3378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3379 if (PetscDefined(USE_DEBUG)) { 3380 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3381 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); 3382 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); 3383 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3384 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); 3385 } 3386 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3387 mesh->cones[off + conePos] = conePoint; 3388 PetscFunctionReturn(PETSC_SUCCESS); 3389 } 3390 3391 /*@ 3392 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3393 3394 Not Collective 3395 3396 Input Parameters: 3397 + dm - The `DMPLEX` 3398 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3399 . conePos - The local index in the cone where the point should be put 3400 - coneOrientation - The point orientation to insert 3401 3402 Level: beginner 3403 3404 Note: 3405 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3406 3407 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3408 @*/ 3409 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3410 { 3411 DM_Plex *mesh = (DM_Plex *)dm->data; 3412 PetscInt pStart, pEnd; 3413 PetscInt dof, off; 3414 3415 PetscFunctionBegin; 3416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3417 if (PetscDefined(USE_DEBUG)) { 3418 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3419 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); 3420 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3421 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); 3422 } 3423 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3424 mesh->coneOrientations[off + conePos] = coneOrientation; 3425 PetscFunctionReturn(PETSC_SUCCESS); 3426 } 3427 3428 /*@C 3429 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3430 3431 Not collective 3432 3433 Input Parameters: 3434 + dm - The DMPlex 3435 - p - The point, which must lie in the chart set with DMPlexSetChart() 3436 3437 Output Parameters: 3438 + cone - An array of points which are on the in-edges for point `p` 3439 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3440 integer giving the prescription for cone traversal. 3441 3442 Level: beginner 3443 3444 Notes: 3445 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3446 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3447 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3448 with the identity. 3449 3450 Fortran Notes: 3451 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3452 `DMPlexRestoreCone()` is not needed/available in C. 3453 3454 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3455 @*/ 3456 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3457 { 3458 DM_Plex *mesh = (DM_Plex *)dm->data; 3459 3460 PetscFunctionBegin; 3461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3462 if (mesh->tr) { 3463 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3464 } else { 3465 PetscInt off; 3466 if (PetscDefined(USE_DEBUG)) { 3467 PetscInt dof; 3468 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3469 if (dof) { 3470 if (cone) PetscAssertPointer(cone, 3); 3471 if (ornt) PetscAssertPointer(ornt, 4); 3472 } 3473 } 3474 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3475 if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB 3476 if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL; 3477 } 3478 PetscFunctionReturn(PETSC_SUCCESS); 3479 } 3480 3481 /*@C 3482 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3483 3484 Not Collective 3485 3486 Input Parameters: 3487 + dm - The DMPlex 3488 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3489 . cone - An array of points which are on the in-edges for point p 3490 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3491 integer giving the prescription for cone traversal. 3492 3493 Level: beginner 3494 3495 Notes: 3496 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3497 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3498 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3499 with the identity. 3500 3501 Fortran Notes: 3502 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3503 `DMPlexRestoreCone()` is not needed/available in C. 3504 3505 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3506 @*/ 3507 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3508 { 3509 DM_Plex *mesh = (DM_Plex *)dm->data; 3510 3511 PetscFunctionBegin; 3512 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3513 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3514 PetscFunctionReturn(PETSC_SUCCESS); 3515 } 3516 3517 /*@ 3518 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3519 3520 Not Collective 3521 3522 Input Parameters: 3523 + dm - The `DMPLEX` 3524 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3525 3526 Output Parameter: 3527 . size - The support size for point `p` 3528 3529 Level: beginner 3530 3531 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3532 @*/ 3533 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3534 { 3535 DM_Plex *mesh = (DM_Plex *)dm->data; 3536 3537 PetscFunctionBegin; 3538 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3539 PetscAssertPointer(size, 3); 3540 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3541 PetscFunctionReturn(PETSC_SUCCESS); 3542 } 3543 3544 /*@ 3545 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3546 3547 Not Collective 3548 3549 Input Parameters: 3550 + dm - The `DMPLEX` 3551 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3552 - size - The support size for point `p` 3553 3554 Level: beginner 3555 3556 Note: 3557 This should be called after `DMPlexSetChart()`. 3558 3559 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3560 @*/ 3561 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3562 { 3563 DM_Plex *mesh = (DM_Plex *)dm->data; 3564 3565 PetscFunctionBegin; 3566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3567 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3568 PetscFunctionReturn(PETSC_SUCCESS); 3569 } 3570 3571 /*@C 3572 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3573 3574 Not Collective 3575 3576 Input Parameters: 3577 + dm - The `DMPLEX` 3578 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3579 3580 Output Parameter: 3581 . support - An array of points which are on the out-edges for point `p` 3582 3583 Level: beginner 3584 3585 Fortran Notes: 3586 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3587 `DMPlexRestoreSupport()` is not needed/available in C. 3588 3589 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3590 @*/ 3591 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3592 { 3593 DM_Plex *mesh = (DM_Plex *)dm->data; 3594 PetscInt off; 3595 3596 PetscFunctionBegin; 3597 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3598 PetscAssertPointer(support, 3); 3599 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3600 *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB 3601 PetscFunctionReturn(PETSC_SUCCESS); 3602 } 3603 3604 /*@ 3605 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3606 3607 Not Collective 3608 3609 Input Parameters: 3610 + dm - The `DMPLEX` 3611 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3612 - support - An array of points which are on the out-edges for point `p` 3613 3614 Level: beginner 3615 3616 Note: 3617 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3618 3619 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3620 @*/ 3621 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3622 { 3623 DM_Plex *mesh = (DM_Plex *)dm->data; 3624 PetscInt pStart, pEnd; 3625 PetscInt dof, off, c; 3626 3627 PetscFunctionBegin; 3628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3629 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3630 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3631 if (dof) PetscAssertPointer(support, 3); 3632 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3633 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); 3634 for (c = 0; c < dof; ++c) { 3635 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); 3636 mesh->supports[off + c] = support[c]; 3637 } 3638 PetscFunctionReturn(PETSC_SUCCESS); 3639 } 3640 3641 /*@ 3642 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3643 3644 Not Collective 3645 3646 Input Parameters: 3647 + dm - The `DMPLEX` 3648 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3649 . supportPos - The local index in the cone where the point should be put 3650 - supportPoint - The mesh point to insert 3651 3652 Level: beginner 3653 3654 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3655 @*/ 3656 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3657 { 3658 DM_Plex *mesh = (DM_Plex *)dm->data; 3659 PetscInt pStart, pEnd; 3660 PetscInt dof, off; 3661 3662 PetscFunctionBegin; 3663 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3664 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3665 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3666 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3667 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); 3668 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); 3669 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); 3670 mesh->supports[off + supportPos] = supportPoint; 3671 PetscFunctionReturn(PETSC_SUCCESS); 3672 } 3673 3674 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3675 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3676 { 3677 switch (ct) { 3678 case DM_POLYTOPE_SEGMENT: 3679 if (o == -1) return -2; 3680 break; 3681 case DM_POLYTOPE_TRIANGLE: 3682 if (o == -3) return -1; 3683 if (o == -2) return -3; 3684 if (o == -1) return -2; 3685 break; 3686 case DM_POLYTOPE_QUADRILATERAL: 3687 if (o == -4) return -2; 3688 if (o == -3) return -1; 3689 if (o == -2) return -4; 3690 if (o == -1) return -3; 3691 break; 3692 default: 3693 return o; 3694 } 3695 return o; 3696 } 3697 3698 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3699 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3700 { 3701 switch (ct) { 3702 case DM_POLYTOPE_SEGMENT: 3703 if ((o == -2) || (o == 1)) return -1; 3704 if (o == -1) return 0; 3705 break; 3706 case DM_POLYTOPE_TRIANGLE: 3707 if (o == -3) return -2; 3708 if (o == -2) return -1; 3709 if (o == -1) return -3; 3710 break; 3711 case DM_POLYTOPE_QUADRILATERAL: 3712 if (o == -4) return -2; 3713 if (o == -3) return -1; 3714 if (o == -2) return -4; 3715 if (o == -1) return -3; 3716 break; 3717 default: 3718 return o; 3719 } 3720 return o; 3721 } 3722 3723 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3724 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3725 { 3726 PetscInt pStart, pEnd, p; 3727 3728 PetscFunctionBegin; 3729 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3730 for (p = pStart; p < pEnd; ++p) { 3731 const PetscInt *cone, *ornt; 3732 PetscInt coneSize, c; 3733 3734 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3735 PetscCall(DMPlexGetCone(dm, p, &cone)); 3736 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3737 for (c = 0; c < coneSize; ++c) { 3738 DMPolytopeType ct; 3739 const PetscInt o = ornt[c]; 3740 3741 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3742 switch (ct) { 3743 case DM_POLYTOPE_SEGMENT: 3744 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3745 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3746 break; 3747 case DM_POLYTOPE_TRIANGLE: 3748 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3749 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3750 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3751 break; 3752 case DM_POLYTOPE_QUADRILATERAL: 3753 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3754 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3755 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3756 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3757 break; 3758 default: 3759 break; 3760 } 3761 } 3762 } 3763 PetscFunctionReturn(PETSC_SUCCESS); 3764 } 3765 3766 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3767 { 3768 DM_Plex *mesh = (DM_Plex *)dm->data; 3769 3770 PetscFunctionBeginHot; 3771 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3772 if (useCone) { 3773 PetscCall(DMPlexGetConeSize(dm, p, size)); 3774 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3775 } else { 3776 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3777 PetscCall(DMPlexGetSupport(dm, p, arr)); 3778 } 3779 } else { 3780 if (useCone) { 3781 const PetscSection s = mesh->coneSection; 3782 const PetscInt ps = p - s->pStart; 3783 const PetscInt off = s->atlasOff[ps]; 3784 3785 *size = s->atlasDof[ps]; 3786 *arr = mesh->cones + off; 3787 *ornt = mesh->coneOrientations + off; 3788 } else { 3789 const PetscSection s = mesh->supportSection; 3790 const PetscInt ps = p - s->pStart; 3791 const PetscInt off = s->atlasOff[ps]; 3792 3793 *size = s->atlasDof[ps]; 3794 *arr = mesh->supports + off; 3795 } 3796 } 3797 PetscFunctionReturn(PETSC_SUCCESS); 3798 } 3799 3800 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3801 { 3802 DM_Plex *mesh = (DM_Plex *)dm->data; 3803 3804 PetscFunctionBeginHot; 3805 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3806 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3807 } 3808 PetscFunctionReturn(PETSC_SUCCESS); 3809 } 3810 3811 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3812 { 3813 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3814 PetscInt *closure; 3815 const PetscInt *tmp = NULL, *tmpO = NULL; 3816 PetscInt off = 0, tmpSize, t; 3817 3818 PetscFunctionBeginHot; 3819 if (ornt) { 3820 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3821 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3822 } 3823 if (*points) { 3824 closure = *points; 3825 } else { 3826 PetscInt maxConeSize, maxSupportSize; 3827 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3828 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3829 } 3830 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3831 if (ct == DM_POLYTOPE_UNKNOWN) { 3832 closure[off++] = p; 3833 closure[off++] = 0; 3834 for (t = 0; t < tmpSize; ++t) { 3835 closure[off++] = tmp[t]; 3836 closure[off++] = tmpO ? tmpO[t] : 0; 3837 } 3838 } else { 3839 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3840 3841 /* We assume that cells with a valid type have faces with a valid type */ 3842 closure[off++] = p; 3843 closure[off++] = ornt; 3844 for (t = 0; t < tmpSize; ++t) { 3845 DMPolytopeType ft; 3846 3847 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3848 closure[off++] = tmp[arr[t]]; 3849 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3850 } 3851 } 3852 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3853 if (numPoints) *numPoints = tmpSize + 1; 3854 if (points) *points = closure; 3855 PetscFunctionReturn(PETSC_SUCCESS); 3856 } 3857 3858 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3859 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3860 { 3861 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3862 const PetscInt *cone, *ornt; 3863 PetscInt *pts, *closure = NULL; 3864 DMPolytopeType ft; 3865 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3866 PetscInt dim, coneSize, c, d, clSize, cl; 3867 3868 PetscFunctionBeginHot; 3869 PetscCall(DMGetDimension(dm, &dim)); 3870 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3871 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3872 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3873 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3874 maxSize = PetscMax(coneSeries, supportSeries); 3875 if (*points) { 3876 pts = *points; 3877 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3878 c = 0; 3879 pts[c++] = point; 3880 pts[c++] = o; 3881 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3882 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3883 for (cl = 0; cl < clSize * 2; cl += 2) { 3884 pts[c++] = closure[cl]; 3885 pts[c++] = closure[cl + 1]; 3886 } 3887 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3888 for (cl = 0; cl < clSize * 2; cl += 2) { 3889 pts[c++] = closure[cl]; 3890 pts[c++] = closure[cl + 1]; 3891 } 3892 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3893 for (d = 2; d < coneSize; ++d) { 3894 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3895 pts[c++] = cone[arr[d * 2 + 0]]; 3896 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3897 } 3898 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3899 if (dim >= 3) { 3900 for (d = 2; d < coneSize; ++d) { 3901 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3902 const PetscInt *fcone, *fornt; 3903 PetscInt fconeSize, fc, i; 3904 3905 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3906 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3907 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3908 for (fc = 0; fc < fconeSize; ++fc) { 3909 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3910 const PetscInt co = farr[fc * 2 + 1]; 3911 3912 for (i = 0; i < c; i += 2) 3913 if (pts[i] == cp) break; 3914 if (i == c) { 3915 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3916 pts[c++] = cp; 3917 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3918 } 3919 } 3920 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3921 } 3922 } 3923 *numPoints = c / 2; 3924 *points = pts; 3925 PetscFunctionReturn(PETSC_SUCCESS); 3926 } 3927 3928 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3929 { 3930 DMPolytopeType ct; 3931 PetscInt *closure, *fifo; 3932 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3933 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3934 PetscInt depth, maxSize; 3935 3936 PetscFunctionBeginHot; 3937 PetscCall(DMPlexGetDepth(dm, &depth)); 3938 if (depth == 1) { 3939 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3940 PetscFunctionReturn(PETSC_SUCCESS); 3941 } 3942 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3943 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3944 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3945 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3946 PetscFunctionReturn(PETSC_SUCCESS); 3947 } 3948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3949 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3950 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3951 maxSize = PetscMax(coneSeries, supportSeries); 3952 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3953 if (*points) { 3954 closure = *points; 3955 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3956 closure[closureSize++] = p; 3957 closure[closureSize++] = ornt; 3958 fifo[fifoSize++] = p; 3959 fifo[fifoSize++] = ornt; 3960 fifo[fifoSize++] = ct; 3961 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3962 while (fifoSize - fifoStart) { 3963 const PetscInt q = fifo[fifoStart++]; 3964 const PetscInt o = fifo[fifoStart++]; 3965 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3966 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3967 const PetscInt *tmp, *tmpO = NULL; 3968 PetscInt tmpSize, t; 3969 3970 if (PetscDefined(USE_DEBUG)) { 3971 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3972 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); 3973 } 3974 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3975 for (t = 0; t < tmpSize; ++t) { 3976 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3977 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3978 const PetscInt cp = tmp[ip]; 3979 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3980 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3981 PetscInt c; 3982 3983 /* Check for duplicate */ 3984 for (c = 0; c < closureSize; c += 2) { 3985 if (closure[c] == cp) break; 3986 } 3987 if (c == closureSize) { 3988 closure[closureSize++] = cp; 3989 closure[closureSize++] = co; 3990 fifo[fifoSize++] = cp; 3991 fifo[fifoSize++] = co; 3992 fifo[fifoSize++] = ct; 3993 } 3994 } 3995 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3996 } 3997 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3998 if (numPoints) *numPoints = closureSize / 2; 3999 if (points) *points = closure; 4000 PetscFunctionReturn(PETSC_SUCCESS); 4001 } 4002 4003 /*@C 4004 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4005 4006 Not Collective 4007 4008 Input Parameters: 4009 + dm - The `DMPLEX` 4010 . p - The mesh point 4011 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4012 4013 Input/Output Parameter: 4014 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4015 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4016 4017 Output Parameter: 4018 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4019 4020 Level: beginner 4021 4022 Note: 4023 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4024 4025 Fortran Notes: 4026 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4027 4028 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4029 @*/ 4030 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4031 { 4032 PetscFunctionBeginHot; 4033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4034 if (numPoints) PetscAssertPointer(numPoints, 4); 4035 if (points) PetscAssertPointer(points, 5); 4036 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4037 PetscFunctionReturn(PETSC_SUCCESS); 4038 } 4039 4040 /*@C 4041 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4042 4043 Not Collective 4044 4045 Input Parameters: 4046 + dm - The `DMPLEX` 4047 . p - The mesh point 4048 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4049 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4050 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4051 4052 Level: beginner 4053 4054 Note: 4055 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4056 4057 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4058 @*/ 4059 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4060 { 4061 PetscFunctionBeginHot; 4062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4063 if (numPoints) *numPoints = 0; 4064 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4065 PetscFunctionReturn(PETSC_SUCCESS); 4066 } 4067 4068 /*@ 4069 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4070 4071 Not Collective 4072 4073 Input Parameter: 4074 . dm - The `DMPLEX` 4075 4076 Output Parameters: 4077 + maxConeSize - The maximum number of in-edges 4078 - maxSupportSize - The maximum number of out-edges 4079 4080 Level: beginner 4081 4082 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4083 @*/ 4084 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4085 { 4086 DM_Plex *mesh = (DM_Plex *)dm->data; 4087 4088 PetscFunctionBegin; 4089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4090 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4091 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4092 PetscFunctionReturn(PETSC_SUCCESS); 4093 } 4094 4095 PetscErrorCode DMSetUp_Plex(DM dm) 4096 { 4097 DM_Plex *mesh = (DM_Plex *)dm->data; 4098 PetscInt size, maxSupportSize; 4099 4100 PetscFunctionBegin; 4101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4102 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4103 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4104 PetscCall(PetscMalloc1(size, &mesh->cones)); 4105 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4106 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4107 if (maxSupportSize) { 4108 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4109 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4110 PetscCall(PetscMalloc1(size, &mesh->supports)); 4111 } 4112 PetscFunctionReturn(PETSC_SUCCESS); 4113 } 4114 4115 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4116 { 4117 PetscFunctionBegin; 4118 if (subdm) PetscCall(DMClone(dm, subdm)); 4119 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 4120 if (subdm) (*subdm)->useNatural = dm->useNatural; 4121 if (dm->useNatural && dm->sfMigration) { 4122 PetscSF sfNatural; 4123 4124 (*subdm)->sfMigration = dm->sfMigration; 4125 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4126 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4127 (*subdm)->sfNatural = sfNatural; 4128 } 4129 PetscFunctionReturn(PETSC_SUCCESS); 4130 } 4131 4132 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4133 { 4134 PetscInt i = 0; 4135 4136 PetscFunctionBegin; 4137 PetscCall(DMClone(dms[0], superdm)); 4138 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4139 (*superdm)->useNatural = PETSC_FALSE; 4140 for (i = 0; i < len; i++) { 4141 if (dms[i]->useNatural && dms[i]->sfMigration) { 4142 PetscSF sfNatural; 4143 4144 (*superdm)->sfMigration = dms[i]->sfMigration; 4145 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4146 (*superdm)->useNatural = PETSC_TRUE; 4147 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4148 (*superdm)->sfNatural = sfNatural; 4149 break; 4150 } 4151 } 4152 PetscFunctionReturn(PETSC_SUCCESS); 4153 } 4154 4155 /*@ 4156 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4157 4158 Not Collective 4159 4160 Input Parameter: 4161 . dm - The `DMPLEX` 4162 4163 Level: beginner 4164 4165 Note: 4166 This should be called after all calls to `DMPlexSetCone()` 4167 4168 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4169 @*/ 4170 PetscErrorCode DMPlexSymmetrize(DM dm) 4171 { 4172 DM_Plex *mesh = (DM_Plex *)dm->data; 4173 PetscInt *offsets; 4174 PetscInt supportSize; 4175 PetscInt pStart, pEnd, p; 4176 4177 PetscFunctionBegin; 4178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4179 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4180 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4181 /* Calculate support sizes */ 4182 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4183 for (p = pStart; p < pEnd; ++p) { 4184 PetscInt dof, off, c; 4185 4186 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4187 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4188 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4189 } 4190 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4191 /* Calculate supports */ 4192 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4193 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4194 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4195 for (p = pStart; p < pEnd; ++p) { 4196 PetscInt dof, off, c; 4197 4198 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4199 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4200 for (c = off; c < off + dof; ++c) { 4201 const PetscInt q = mesh->cones[c]; 4202 PetscInt offS; 4203 4204 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4205 4206 mesh->supports[offS + offsets[q]] = p; 4207 ++offsets[q]; 4208 } 4209 } 4210 PetscCall(PetscFree(offsets)); 4211 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4212 PetscFunctionReturn(PETSC_SUCCESS); 4213 } 4214 4215 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4216 { 4217 IS stratumIS; 4218 4219 PetscFunctionBegin; 4220 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4221 if (PetscDefined(USE_DEBUG)) { 4222 PetscInt qStart, qEnd, numLevels, level; 4223 PetscBool overlap = PETSC_FALSE; 4224 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4225 for (level = 0; level < numLevels; level++) { 4226 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4227 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4228 overlap = PETSC_TRUE; 4229 break; 4230 } 4231 } 4232 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); 4233 } 4234 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4235 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4236 PetscCall(ISDestroy(&stratumIS)); 4237 PetscFunctionReturn(PETSC_SUCCESS); 4238 } 4239 4240 /*@ 4241 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4242 4243 Collective 4244 4245 Input Parameter: 4246 . dm - The `DMPLEX` 4247 4248 Level: beginner 4249 4250 Notes: 4251 The strata group all points of the same grade, and this function calculates the strata. This 4252 grade can be seen as the height (or depth) of the point in the DAG. 4253 4254 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4255 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4256 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4257 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4258 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4259 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4260 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4261 4262 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4263 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4264 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 4265 to interpolate only that one (e0), so that 4266 .vb 4267 cone(c0) = {e0, v2} 4268 cone(e0) = {v0, v1} 4269 .ve 4270 If `DMPlexStratify()` is run on this mesh, it will give depths 4271 .vb 4272 depth 0 = {v0, v1, v2} 4273 depth 1 = {e0, c0} 4274 .ve 4275 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4276 4277 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4278 4279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4280 @*/ 4281 PetscErrorCode DMPlexStratify(DM dm) 4282 { 4283 DM_Plex *mesh = (DM_Plex *)dm->data; 4284 DMLabel label; 4285 PetscInt pStart, pEnd, p; 4286 PetscInt numRoots = 0, numLeaves = 0; 4287 4288 PetscFunctionBegin; 4289 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4290 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4291 4292 /* Create depth label */ 4293 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4294 PetscCall(DMCreateLabel(dm, "depth")); 4295 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4296 4297 { 4298 /* Initialize roots and count leaves */ 4299 PetscInt sMin = PETSC_MAX_INT; 4300 PetscInt sMax = PETSC_MIN_INT; 4301 PetscInt coneSize, supportSize; 4302 4303 for (p = pStart; p < pEnd; ++p) { 4304 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4305 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4306 if (!coneSize && supportSize) { 4307 sMin = PetscMin(p, sMin); 4308 sMax = PetscMax(p, sMax); 4309 ++numRoots; 4310 } else if (!supportSize && coneSize) { 4311 ++numLeaves; 4312 } else if (!supportSize && !coneSize) { 4313 /* Isolated points */ 4314 sMin = PetscMin(p, sMin); 4315 sMax = PetscMax(p, sMax); 4316 } 4317 } 4318 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4319 } 4320 4321 if (numRoots + numLeaves == (pEnd - pStart)) { 4322 PetscInt sMin = PETSC_MAX_INT; 4323 PetscInt sMax = PETSC_MIN_INT; 4324 PetscInt coneSize, supportSize; 4325 4326 for (p = pStart; p < pEnd; ++p) { 4327 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4328 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4329 if (!supportSize && coneSize) { 4330 sMin = PetscMin(p, sMin); 4331 sMax = PetscMax(p, sMax); 4332 } 4333 } 4334 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4335 } else { 4336 PetscInt level = 0; 4337 PetscInt qStart, qEnd, q; 4338 4339 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4340 while (qEnd > qStart) { 4341 PetscInt sMin = PETSC_MAX_INT; 4342 PetscInt sMax = PETSC_MIN_INT; 4343 4344 for (q = qStart; q < qEnd; ++q) { 4345 const PetscInt *support; 4346 PetscInt supportSize, s; 4347 4348 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4349 PetscCall(DMPlexGetSupport(dm, q, &support)); 4350 for (s = 0; s < supportSize; ++s) { 4351 sMin = PetscMin(support[s], sMin); 4352 sMax = PetscMax(support[s], sMax); 4353 } 4354 } 4355 PetscCall(DMLabelGetNumValues(label, &level)); 4356 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4357 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4358 } 4359 } 4360 { /* just in case there is an empty process */ 4361 PetscInt numValues, maxValues = 0, v; 4362 4363 PetscCall(DMLabelGetNumValues(label, &numValues)); 4364 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4365 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4366 } 4367 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4368 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4369 PetscFunctionReturn(PETSC_SUCCESS); 4370 } 4371 4372 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4373 { 4374 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4375 PetscInt dim, depth, pheight, coneSize; 4376 4377 PetscFunctionBeginHot; 4378 PetscCall(DMGetDimension(dm, &dim)); 4379 PetscCall(DMPlexGetDepth(dm, &depth)); 4380 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4381 pheight = depth - pdepth; 4382 if (depth <= 1) { 4383 switch (pdepth) { 4384 case 0: 4385 ct = DM_POLYTOPE_POINT; 4386 break; 4387 case 1: 4388 switch (coneSize) { 4389 case 2: 4390 ct = DM_POLYTOPE_SEGMENT; 4391 break; 4392 case 3: 4393 ct = DM_POLYTOPE_TRIANGLE; 4394 break; 4395 case 4: 4396 switch (dim) { 4397 case 2: 4398 ct = DM_POLYTOPE_QUADRILATERAL; 4399 break; 4400 case 3: 4401 ct = DM_POLYTOPE_TETRAHEDRON; 4402 break; 4403 default: 4404 break; 4405 } 4406 break; 4407 case 5: 4408 ct = DM_POLYTOPE_PYRAMID; 4409 break; 4410 case 6: 4411 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4412 break; 4413 case 8: 4414 ct = DM_POLYTOPE_HEXAHEDRON; 4415 break; 4416 default: 4417 break; 4418 } 4419 } 4420 } else { 4421 if (pdepth == 0) { 4422 ct = DM_POLYTOPE_POINT; 4423 } else if (pheight == 0) { 4424 switch (dim) { 4425 case 1: 4426 switch (coneSize) { 4427 case 2: 4428 ct = DM_POLYTOPE_SEGMENT; 4429 break; 4430 default: 4431 break; 4432 } 4433 break; 4434 case 2: 4435 switch (coneSize) { 4436 case 3: 4437 ct = DM_POLYTOPE_TRIANGLE; 4438 break; 4439 case 4: 4440 ct = DM_POLYTOPE_QUADRILATERAL; 4441 break; 4442 default: 4443 break; 4444 } 4445 break; 4446 case 3: 4447 switch (coneSize) { 4448 case 4: 4449 ct = DM_POLYTOPE_TETRAHEDRON; 4450 break; 4451 case 5: { 4452 const PetscInt *cone; 4453 PetscInt faceConeSize; 4454 4455 PetscCall(DMPlexGetCone(dm, p, &cone)); 4456 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4457 switch (faceConeSize) { 4458 case 3: 4459 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4460 break; 4461 case 4: 4462 ct = DM_POLYTOPE_PYRAMID; 4463 break; 4464 } 4465 } break; 4466 case 6: 4467 ct = DM_POLYTOPE_HEXAHEDRON; 4468 break; 4469 default: 4470 break; 4471 } 4472 break; 4473 default: 4474 break; 4475 } 4476 } else if (pheight > 0) { 4477 switch (coneSize) { 4478 case 2: 4479 ct = DM_POLYTOPE_SEGMENT; 4480 break; 4481 case 3: 4482 ct = DM_POLYTOPE_TRIANGLE; 4483 break; 4484 case 4: 4485 ct = DM_POLYTOPE_QUADRILATERAL; 4486 break; 4487 default: 4488 break; 4489 } 4490 } 4491 } 4492 *pt = ct; 4493 PetscFunctionReturn(PETSC_SUCCESS); 4494 } 4495 4496 /*@ 4497 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4498 4499 Collective 4500 4501 Input Parameter: 4502 . dm - The `DMPLEX` 4503 4504 Level: developer 4505 4506 Note: 4507 This function is normally called automatically when a cell type is requested. It creates an 4508 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4509 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4510 4511 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4512 4513 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4514 @*/ 4515 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4516 { 4517 DM_Plex *mesh; 4518 DMLabel ctLabel; 4519 PetscInt pStart, pEnd, p; 4520 4521 PetscFunctionBegin; 4522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4523 mesh = (DM_Plex *)dm->data; 4524 PetscCall(DMCreateLabel(dm, "celltype")); 4525 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4526 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4527 PetscCall(PetscFree(mesh->cellTypes)); 4528 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4529 for (p = pStart; p < pEnd; ++p) { 4530 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4531 PetscInt pdepth; 4532 4533 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4534 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4535 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4536 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4537 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4538 } 4539 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4540 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4541 PetscFunctionReturn(PETSC_SUCCESS); 4542 } 4543 4544 /*@C 4545 DMPlexGetJoin - Get an array for the join of the set of points 4546 4547 Not Collective 4548 4549 Input Parameters: 4550 + dm - The `DMPLEX` object 4551 . numPoints - The number of input points for the join 4552 - points - The input points 4553 4554 Output Parameters: 4555 + numCoveredPoints - The number of points in the join 4556 - coveredPoints - The points in the join 4557 4558 Level: intermediate 4559 4560 Note: 4561 Currently, this is restricted to a single level join 4562 4563 Fortran Notes: 4564 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4565 4566 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4567 @*/ 4568 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4569 { 4570 DM_Plex *mesh = (DM_Plex *)dm->data; 4571 PetscInt *join[2]; 4572 PetscInt joinSize, i = 0; 4573 PetscInt dof, off, p, c, m; 4574 PetscInt maxSupportSize; 4575 4576 PetscFunctionBegin; 4577 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4578 PetscAssertPointer(points, 3); 4579 PetscAssertPointer(numCoveredPoints, 4); 4580 PetscAssertPointer(coveredPoints, 5); 4581 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4582 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4583 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4584 /* Copy in support of first point */ 4585 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4586 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4587 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4588 /* Check each successive support */ 4589 for (p = 1; p < numPoints; ++p) { 4590 PetscInt newJoinSize = 0; 4591 4592 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4593 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4594 for (c = 0; c < dof; ++c) { 4595 const PetscInt point = mesh->supports[off + c]; 4596 4597 for (m = 0; m < joinSize; ++m) { 4598 if (point == join[i][m]) { 4599 join[1 - i][newJoinSize++] = point; 4600 break; 4601 } 4602 } 4603 } 4604 joinSize = newJoinSize; 4605 i = 1 - i; 4606 } 4607 *numCoveredPoints = joinSize; 4608 *coveredPoints = join[i]; 4609 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4610 PetscFunctionReturn(PETSC_SUCCESS); 4611 } 4612 4613 /*@C 4614 DMPlexRestoreJoin - Restore an array for the join of the set of points 4615 4616 Not Collective 4617 4618 Input Parameters: 4619 + dm - The `DMPLEX` object 4620 . numPoints - The number of input points for the join 4621 - points - The input points 4622 4623 Output Parameters: 4624 + numCoveredPoints - The number of points in the join 4625 - coveredPoints - The points in the join 4626 4627 Level: intermediate 4628 4629 Fortran Notes: 4630 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4631 4632 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4633 @*/ 4634 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4635 { 4636 PetscFunctionBegin; 4637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4638 if (points) PetscAssertPointer(points, 3); 4639 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4640 PetscAssertPointer(coveredPoints, 5); 4641 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4642 if (numCoveredPoints) *numCoveredPoints = 0; 4643 PetscFunctionReturn(PETSC_SUCCESS); 4644 } 4645 4646 /*@C 4647 DMPlexGetFullJoin - Get an array for the join of the set of points 4648 4649 Not Collective 4650 4651 Input Parameters: 4652 + dm - The `DMPLEX` object 4653 . numPoints - The number of input points for the join 4654 - points - The input points 4655 4656 Output Parameters: 4657 + numCoveredPoints - The number of points in the join 4658 - coveredPoints - The points in the join 4659 4660 Level: intermediate 4661 4662 Fortran Notes: 4663 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4664 4665 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4666 @*/ 4667 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4668 { 4669 PetscInt *offsets, **closures; 4670 PetscInt *join[2]; 4671 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4672 PetscInt p, d, c, m, ms; 4673 4674 PetscFunctionBegin; 4675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4676 PetscAssertPointer(points, 3); 4677 PetscAssertPointer(numCoveredPoints, 4); 4678 PetscAssertPointer(coveredPoints, 5); 4679 4680 PetscCall(DMPlexGetDepth(dm, &depth)); 4681 PetscCall(PetscCalloc1(numPoints, &closures)); 4682 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4683 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4684 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4685 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4686 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4687 4688 for (p = 0; p < numPoints; ++p) { 4689 PetscInt closureSize; 4690 4691 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4692 4693 offsets[p * (depth + 2) + 0] = 0; 4694 for (d = 0; d < depth + 1; ++d) { 4695 PetscInt pStart, pEnd, i; 4696 4697 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4698 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4699 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4700 offsets[p * (depth + 2) + d + 1] = i; 4701 break; 4702 } 4703 } 4704 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4705 } 4706 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); 4707 } 4708 for (d = 0; d < depth + 1; ++d) { 4709 PetscInt dof; 4710 4711 /* Copy in support of first point */ 4712 dof = offsets[d + 1] - offsets[d]; 4713 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4714 /* Check each successive cone */ 4715 for (p = 1; p < numPoints && joinSize; ++p) { 4716 PetscInt newJoinSize = 0; 4717 4718 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4719 for (c = 0; c < dof; ++c) { 4720 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4721 4722 for (m = 0; m < joinSize; ++m) { 4723 if (point == join[i][m]) { 4724 join[1 - i][newJoinSize++] = point; 4725 break; 4726 } 4727 } 4728 } 4729 joinSize = newJoinSize; 4730 i = 1 - i; 4731 } 4732 if (joinSize) break; 4733 } 4734 *numCoveredPoints = joinSize; 4735 *coveredPoints = join[i]; 4736 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4737 PetscCall(PetscFree(closures)); 4738 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4739 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4740 PetscFunctionReturn(PETSC_SUCCESS); 4741 } 4742 4743 /*@C 4744 DMPlexGetMeet - Get an array for the meet of the set of points 4745 4746 Not Collective 4747 4748 Input Parameters: 4749 + dm - The `DMPLEX` object 4750 . numPoints - The number of input points for the meet 4751 - points - The input points 4752 4753 Output Parameters: 4754 + numCoveringPoints - The number of points in the meet 4755 - coveringPoints - The points in the meet 4756 4757 Level: intermediate 4758 4759 Note: 4760 Currently, this is restricted to a single level meet 4761 4762 Fortran Notes: 4763 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4764 4765 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4766 @*/ 4767 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4768 { 4769 DM_Plex *mesh = (DM_Plex *)dm->data; 4770 PetscInt *meet[2]; 4771 PetscInt meetSize, i = 0; 4772 PetscInt dof, off, p, c, m; 4773 PetscInt maxConeSize; 4774 4775 PetscFunctionBegin; 4776 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4777 PetscAssertPointer(points, 3); 4778 PetscAssertPointer(numCoveringPoints, 4); 4779 PetscAssertPointer(coveringPoints, 5); 4780 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4781 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4782 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4783 /* Copy in cone of first point */ 4784 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4785 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4786 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4787 /* Check each successive cone */ 4788 for (p = 1; p < numPoints; ++p) { 4789 PetscInt newMeetSize = 0; 4790 4791 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4792 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4793 for (c = 0; c < dof; ++c) { 4794 const PetscInt point = mesh->cones[off + c]; 4795 4796 for (m = 0; m < meetSize; ++m) { 4797 if (point == meet[i][m]) { 4798 meet[1 - i][newMeetSize++] = point; 4799 break; 4800 } 4801 } 4802 } 4803 meetSize = newMeetSize; 4804 i = 1 - i; 4805 } 4806 *numCoveringPoints = meetSize; 4807 *coveringPoints = meet[i]; 4808 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4809 PetscFunctionReturn(PETSC_SUCCESS); 4810 } 4811 4812 /*@C 4813 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4814 4815 Not Collective 4816 4817 Input Parameters: 4818 + dm - The `DMPLEX` object 4819 . numPoints - The number of input points for the meet 4820 - points - The input points 4821 4822 Output Parameters: 4823 + numCoveredPoints - The number of points in the meet 4824 - coveredPoints - The points in the meet 4825 4826 Level: intermediate 4827 4828 Fortran Notes: 4829 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4830 4831 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4832 @*/ 4833 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4834 { 4835 PetscFunctionBegin; 4836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4837 if (points) PetscAssertPointer(points, 3); 4838 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4839 PetscAssertPointer(coveredPoints, 5); 4840 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4841 if (numCoveredPoints) *numCoveredPoints = 0; 4842 PetscFunctionReturn(PETSC_SUCCESS); 4843 } 4844 4845 /*@C 4846 DMPlexGetFullMeet - Get an array for the meet of the set of points 4847 4848 Not Collective 4849 4850 Input Parameters: 4851 + dm - The `DMPLEX` object 4852 . numPoints - The number of input points for the meet 4853 - points - The input points 4854 4855 Output Parameters: 4856 + numCoveredPoints - The number of points in the meet 4857 - coveredPoints - The points in the meet 4858 4859 Level: intermediate 4860 4861 Fortran Notes: 4862 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4863 4864 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4865 @*/ 4866 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4867 { 4868 PetscInt *offsets, **closures; 4869 PetscInt *meet[2]; 4870 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4871 PetscInt p, h, c, m, mc; 4872 4873 PetscFunctionBegin; 4874 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4875 PetscAssertPointer(points, 3); 4876 PetscAssertPointer(numCoveredPoints, 4); 4877 PetscAssertPointer(coveredPoints, 5); 4878 4879 PetscCall(DMPlexGetDepth(dm, &height)); 4880 PetscCall(PetscMalloc1(numPoints, &closures)); 4881 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4882 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4883 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4884 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4885 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4886 4887 for (p = 0; p < numPoints; ++p) { 4888 PetscInt closureSize; 4889 4890 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4891 4892 offsets[p * (height + 2) + 0] = 0; 4893 for (h = 0; h < height + 1; ++h) { 4894 PetscInt pStart, pEnd, i; 4895 4896 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4897 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4898 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4899 offsets[p * (height + 2) + h + 1] = i; 4900 break; 4901 } 4902 } 4903 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4904 } 4905 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); 4906 } 4907 for (h = 0; h < height + 1; ++h) { 4908 PetscInt dof; 4909 4910 /* Copy in cone of first point */ 4911 dof = offsets[h + 1] - offsets[h]; 4912 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4913 /* Check each successive cone */ 4914 for (p = 1; p < numPoints && meetSize; ++p) { 4915 PetscInt newMeetSize = 0; 4916 4917 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4918 for (c = 0; c < dof; ++c) { 4919 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4920 4921 for (m = 0; m < meetSize; ++m) { 4922 if (point == meet[i][m]) { 4923 meet[1 - i][newMeetSize++] = point; 4924 break; 4925 } 4926 } 4927 } 4928 meetSize = newMeetSize; 4929 i = 1 - i; 4930 } 4931 if (meetSize) break; 4932 } 4933 *numCoveredPoints = meetSize; 4934 *coveredPoints = meet[i]; 4935 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4936 PetscCall(PetscFree(closures)); 4937 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4938 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4939 PetscFunctionReturn(PETSC_SUCCESS); 4940 } 4941 4942 /*@C 4943 DMPlexEqual - Determine if two `DM` have the same topology 4944 4945 Not Collective 4946 4947 Input Parameters: 4948 + dmA - A `DMPLEX` object 4949 - dmB - A `DMPLEX` object 4950 4951 Output Parameter: 4952 . equal - `PETSC_TRUE` if the topologies are identical 4953 4954 Level: intermediate 4955 4956 Note: 4957 We are not solving graph isomorphism, so we do not permute. 4958 4959 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4960 @*/ 4961 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4962 { 4963 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4964 4965 PetscFunctionBegin; 4966 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4967 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4968 PetscAssertPointer(equal, 3); 4969 4970 *equal = PETSC_FALSE; 4971 PetscCall(DMPlexGetDepth(dmA, &depth)); 4972 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4973 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 4974 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4975 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4976 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 4977 for (p = pStart; p < pEnd; ++p) { 4978 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4979 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4980 4981 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4982 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4983 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4984 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4985 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4986 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4987 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4988 for (c = 0; c < coneSize; ++c) { 4989 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4990 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4991 } 4992 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4993 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4994 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4995 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4996 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4997 for (s = 0; s < supportSize; ++s) { 4998 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 4999 } 5000 } 5001 *equal = PETSC_TRUE; 5002 PetscFunctionReturn(PETSC_SUCCESS); 5003 } 5004 5005 /*@C 5006 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5007 5008 Not Collective 5009 5010 Input Parameters: 5011 + dm - The `DMPLEX` 5012 . cellDim - The cell dimension 5013 - numCorners - The number of vertices on a cell 5014 5015 Output Parameter: 5016 . numFaceVertices - The number of vertices on a face 5017 5018 Level: developer 5019 5020 Note: 5021 Of course this can only work for a restricted set of symmetric shapes 5022 5023 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5024 @*/ 5025 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5026 { 5027 MPI_Comm comm; 5028 5029 PetscFunctionBegin; 5030 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5031 PetscAssertPointer(numFaceVertices, 4); 5032 switch (cellDim) { 5033 case 0: 5034 *numFaceVertices = 0; 5035 break; 5036 case 1: 5037 *numFaceVertices = 1; 5038 break; 5039 case 2: 5040 switch (numCorners) { 5041 case 3: /* triangle */ 5042 *numFaceVertices = 2; /* Edge has 2 vertices */ 5043 break; 5044 case 4: /* quadrilateral */ 5045 *numFaceVertices = 2; /* Edge has 2 vertices */ 5046 break; 5047 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5048 *numFaceVertices = 3; /* Edge has 3 vertices */ 5049 break; 5050 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5051 *numFaceVertices = 3; /* Edge has 3 vertices */ 5052 break; 5053 default: 5054 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5055 } 5056 break; 5057 case 3: 5058 switch (numCorners) { 5059 case 4: /* tetradehdron */ 5060 *numFaceVertices = 3; /* Face has 3 vertices */ 5061 break; 5062 case 6: /* tet cohesive cells */ 5063 *numFaceVertices = 4; /* Face has 4 vertices */ 5064 break; 5065 case 8: /* hexahedron */ 5066 *numFaceVertices = 4; /* Face has 4 vertices */ 5067 break; 5068 case 9: /* tet cohesive Lagrange cells */ 5069 *numFaceVertices = 6; /* Face has 6 vertices */ 5070 break; 5071 case 10: /* quadratic tetrahedron */ 5072 *numFaceVertices = 6; /* Face has 6 vertices */ 5073 break; 5074 case 12: /* hex cohesive Lagrange cells */ 5075 *numFaceVertices = 6; /* Face has 6 vertices */ 5076 break; 5077 case 18: /* quadratic tet cohesive Lagrange cells */ 5078 *numFaceVertices = 6; /* Face has 6 vertices */ 5079 break; 5080 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5081 *numFaceVertices = 9; /* Face has 9 vertices */ 5082 break; 5083 default: 5084 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5085 } 5086 break; 5087 default: 5088 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5089 } 5090 PetscFunctionReturn(PETSC_SUCCESS); 5091 } 5092 5093 /*@ 5094 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5095 5096 Not Collective 5097 5098 Input Parameter: 5099 . dm - The `DMPLEX` object 5100 5101 Output Parameter: 5102 . depthLabel - The `DMLabel` recording point depth 5103 5104 Level: developer 5105 5106 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5107 @*/ 5108 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5109 { 5110 PetscFunctionBegin; 5111 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5112 PetscAssertPointer(depthLabel, 2); 5113 *depthLabel = dm->depthLabel; 5114 PetscFunctionReturn(PETSC_SUCCESS); 5115 } 5116 5117 /*@ 5118 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5119 5120 Not Collective 5121 5122 Input Parameter: 5123 . dm - The `DMPLEX` object 5124 5125 Output Parameter: 5126 . depth - The number of strata (breadth first levels) in the DAG 5127 5128 Level: developer 5129 5130 Notes: 5131 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5132 5133 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5134 5135 An empty mesh gives -1. 5136 5137 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5138 @*/ 5139 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5140 { 5141 DM_Plex *mesh = (DM_Plex *)dm->data; 5142 DMLabel label; 5143 PetscInt d = 0; 5144 5145 PetscFunctionBegin; 5146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5147 PetscAssertPointer(depth, 2); 5148 if (mesh->tr) { 5149 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5150 } else { 5151 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5152 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5153 *depth = d - 1; 5154 } 5155 PetscFunctionReturn(PETSC_SUCCESS); 5156 } 5157 5158 /*@ 5159 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5160 5161 Not Collective 5162 5163 Input Parameters: 5164 + dm - The `DMPLEX` object 5165 - depth - The requested depth 5166 5167 Output Parameters: 5168 + start - The first point at this `depth` 5169 - end - One beyond the last point at this `depth` 5170 5171 Level: developer 5172 5173 Notes: 5174 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5175 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5176 higher dimension, e.g., "edges". 5177 5178 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5179 @*/ 5180 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5181 { 5182 DM_Plex *mesh = (DM_Plex *)dm->data; 5183 DMLabel label; 5184 PetscInt pStart, pEnd; 5185 5186 PetscFunctionBegin; 5187 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5188 if (start) { 5189 PetscAssertPointer(start, 3); 5190 *start = 0; 5191 } 5192 if (end) { 5193 PetscAssertPointer(end, 4); 5194 *end = 0; 5195 } 5196 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5197 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5198 if (depth < 0) { 5199 if (start) *start = pStart; 5200 if (end) *end = pEnd; 5201 PetscFunctionReturn(PETSC_SUCCESS); 5202 } 5203 if (mesh->tr) { 5204 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5205 } else { 5206 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5207 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5208 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5209 } 5210 PetscFunctionReturn(PETSC_SUCCESS); 5211 } 5212 5213 /*@ 5214 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5215 5216 Not Collective 5217 5218 Input Parameters: 5219 + dm - The `DMPLEX` object 5220 - height - The requested height 5221 5222 Output Parameters: 5223 + start - The first point at this `height` 5224 - end - One beyond the last point at this `height` 5225 5226 Level: developer 5227 5228 Notes: 5229 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5230 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5231 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5232 5233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5234 @*/ 5235 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5236 { 5237 DMLabel label; 5238 PetscInt depth, pStart, pEnd; 5239 5240 PetscFunctionBegin; 5241 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5242 if (start) { 5243 PetscAssertPointer(start, 3); 5244 *start = 0; 5245 } 5246 if (end) { 5247 PetscAssertPointer(end, 4); 5248 *end = 0; 5249 } 5250 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5251 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5252 if (height < 0) { 5253 if (start) *start = pStart; 5254 if (end) *end = pEnd; 5255 PetscFunctionReturn(PETSC_SUCCESS); 5256 } 5257 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5258 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5259 else PetscCall(DMGetDimension(dm, &depth)); 5260 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5261 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5262 PetscFunctionReturn(PETSC_SUCCESS); 5263 } 5264 5265 /*@ 5266 DMPlexGetPointDepth - Get the `depth` of a given point 5267 5268 Not Collective 5269 5270 Input Parameters: 5271 + dm - The `DMPLEX` object 5272 - point - The point 5273 5274 Output Parameter: 5275 . depth - The depth of the `point` 5276 5277 Level: intermediate 5278 5279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5280 @*/ 5281 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5282 { 5283 PetscFunctionBegin; 5284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5285 PetscAssertPointer(depth, 3); 5286 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5287 PetscFunctionReturn(PETSC_SUCCESS); 5288 } 5289 5290 /*@ 5291 DMPlexGetPointHeight - Get the `height` of a given point 5292 5293 Not Collective 5294 5295 Input Parameters: 5296 + dm - The `DMPLEX` object 5297 - point - The point 5298 5299 Output Parameter: 5300 . height - The height of the `point` 5301 5302 Level: intermediate 5303 5304 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5305 @*/ 5306 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5307 { 5308 PetscInt n, pDepth; 5309 5310 PetscFunctionBegin; 5311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5312 PetscAssertPointer(height, 3); 5313 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5314 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5315 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5316 PetscFunctionReturn(PETSC_SUCCESS); 5317 } 5318 5319 /*@ 5320 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5321 5322 Not Collective 5323 5324 Input Parameter: 5325 . dm - The `DMPLEX` object 5326 5327 Output Parameter: 5328 . celltypeLabel - The `DMLabel` recording cell polytope type 5329 5330 Level: developer 5331 5332 Note: 5333 This function will trigger automatica computation of cell types. This can be disabled by calling 5334 `DMCreateLabel`(dm, "celltype") beforehand. 5335 5336 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5337 @*/ 5338 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5339 { 5340 PetscFunctionBegin; 5341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5342 PetscAssertPointer(celltypeLabel, 2); 5343 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5344 *celltypeLabel = dm->celltypeLabel; 5345 PetscFunctionReturn(PETSC_SUCCESS); 5346 } 5347 5348 /*@ 5349 DMPlexGetCellType - Get the polytope type of a given cell 5350 5351 Not Collective 5352 5353 Input Parameters: 5354 + dm - The `DMPLEX` object 5355 - cell - The cell 5356 5357 Output Parameter: 5358 . celltype - The polytope type of the cell 5359 5360 Level: intermediate 5361 5362 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5363 @*/ 5364 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5365 { 5366 DM_Plex *mesh = (DM_Plex *)dm->data; 5367 DMLabel label; 5368 PetscInt ct; 5369 5370 PetscFunctionBegin; 5371 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5372 PetscAssertPointer(celltype, 3); 5373 if (mesh->tr) { 5374 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5375 } else { 5376 PetscInt pStart, pEnd; 5377 5378 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5379 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5380 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5381 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5382 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5383 for (PetscInt p = pStart; p < pEnd; p++) { 5384 PetscCall(DMLabelGetValue(label, p, &ct)); 5385 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5386 } 5387 } 5388 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5389 if (PetscDefined(USE_DEBUG)) { 5390 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5391 PetscCall(DMLabelGetValue(label, cell, &ct)); 5392 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5393 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5394 } 5395 } 5396 PetscFunctionReturn(PETSC_SUCCESS); 5397 } 5398 5399 /*@ 5400 DMPlexSetCellType - Set the polytope type of a given cell 5401 5402 Not Collective 5403 5404 Input Parameters: 5405 + dm - The `DMPLEX` object 5406 . cell - The cell 5407 - celltype - The polytope type of the cell 5408 5409 Level: advanced 5410 5411 Note: 5412 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5413 is executed. This function will override the computed type. However, if automatic classification will not succeed 5414 and a user wants to manually specify all types, the classification must be disabled by calling 5415 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5416 5417 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5418 @*/ 5419 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5420 { 5421 DM_Plex *mesh = (DM_Plex *)dm->data; 5422 DMLabel label; 5423 PetscInt pStart, pEnd; 5424 5425 PetscFunctionBegin; 5426 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5427 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5428 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5429 PetscCall(DMLabelSetValue(label, cell, celltype)); 5430 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5431 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5432 PetscFunctionReturn(PETSC_SUCCESS); 5433 } 5434 5435 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5436 { 5437 PetscSection section, s; 5438 Mat m; 5439 PetscInt maxHeight; 5440 const char *prefix; 5441 5442 PetscFunctionBegin; 5443 PetscCall(DMClone(dm, cdm)); 5444 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5445 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5446 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5447 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5448 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5449 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5450 PetscCall(DMSetLocalSection(*cdm, section)); 5451 PetscCall(PetscSectionDestroy(§ion)); 5452 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5453 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5454 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5455 PetscCall(PetscSectionDestroy(&s)); 5456 PetscCall(MatDestroy(&m)); 5457 5458 PetscCall(DMSetNumFields(*cdm, 1)); 5459 PetscCall(DMCreateDS(*cdm)); 5460 (*cdm)->cloneOpts = PETSC_TRUE; 5461 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5462 PetscFunctionReturn(PETSC_SUCCESS); 5463 } 5464 5465 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5466 { 5467 Vec coordsLocal, cellCoordsLocal; 5468 DM coordsDM, cellCoordsDM; 5469 5470 PetscFunctionBegin; 5471 *field = NULL; 5472 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5473 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5474 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5475 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5476 if (coordsLocal && coordsDM) { 5477 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5478 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5479 } 5480 PetscFunctionReturn(PETSC_SUCCESS); 5481 } 5482 5483 /*@C 5484 DMPlexGetConeSection - Return a section which describes the layout of cone data 5485 5486 Not Collective 5487 5488 Input Parameter: 5489 . dm - The `DMPLEX` object 5490 5491 Output Parameter: 5492 . section - The `PetscSection` object 5493 5494 Level: developer 5495 5496 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5497 @*/ 5498 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5499 { 5500 DM_Plex *mesh = (DM_Plex *)dm->data; 5501 5502 PetscFunctionBegin; 5503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5504 if (section) *section = mesh->coneSection; 5505 PetscFunctionReturn(PETSC_SUCCESS); 5506 } 5507 5508 /*@C 5509 DMPlexGetSupportSection - Return a section which describes the layout of support data 5510 5511 Not Collective 5512 5513 Input Parameter: 5514 . dm - The `DMPLEX` object 5515 5516 Output Parameter: 5517 . section - The `PetscSection` object 5518 5519 Level: developer 5520 5521 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5522 @*/ 5523 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5524 { 5525 DM_Plex *mesh = (DM_Plex *)dm->data; 5526 5527 PetscFunctionBegin; 5528 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5529 if (section) *section = mesh->supportSection; 5530 PetscFunctionReturn(PETSC_SUCCESS); 5531 } 5532 5533 /*@C 5534 DMPlexGetCones - Return cone data 5535 5536 Not Collective 5537 5538 Input Parameter: 5539 . dm - The `DMPLEX` object 5540 5541 Output Parameter: 5542 . cones - The cone for each point 5543 5544 Level: developer 5545 5546 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5547 @*/ 5548 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5549 { 5550 DM_Plex *mesh = (DM_Plex *)dm->data; 5551 5552 PetscFunctionBegin; 5553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5554 if (cones) *cones = mesh->cones; 5555 PetscFunctionReturn(PETSC_SUCCESS); 5556 } 5557 5558 /*@C 5559 DMPlexGetConeOrientations - Return cone orientation data 5560 5561 Not Collective 5562 5563 Input Parameter: 5564 . dm - The `DMPLEX` object 5565 5566 Output Parameter: 5567 . coneOrientations - The array of cone orientations for all points 5568 5569 Level: developer 5570 5571 Notes: 5572 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5573 5574 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5575 5576 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5577 @*/ 5578 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5579 { 5580 DM_Plex *mesh = (DM_Plex *)dm->data; 5581 5582 PetscFunctionBegin; 5583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5584 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5585 PetscFunctionReturn(PETSC_SUCCESS); 5586 } 5587 5588 /******************************** FEM Support **********************************/ 5589 5590 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5591 { 5592 PetscInt depth; 5593 5594 PetscFunctionBegin; 5595 PetscCall(DMPlexGetDepth(plex, &depth)); 5596 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5597 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5598 PetscFunctionReturn(PETSC_SUCCESS); 5599 } 5600 5601 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5602 { 5603 PetscInt depth; 5604 5605 PetscFunctionBegin; 5606 PetscCall(DMPlexGetDepth(plex, &depth)); 5607 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5608 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5609 PetscFunctionReturn(PETSC_SUCCESS); 5610 } 5611 5612 /* 5613 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5614 representing a line in the section. 5615 */ 5616 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5617 { 5618 PetscFunctionBeginHot; 5619 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5620 if (line < 0) { 5621 *k = 0; 5622 *Nc = 0; 5623 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5624 *k = 1; 5625 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5626 /* An order k SEM disc has k-1 dofs on an edge */ 5627 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5628 *k = *k / *Nc + 1; 5629 } 5630 PetscFunctionReturn(PETSC_SUCCESS); 5631 } 5632 5633 /*@ 5634 5635 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5636 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5637 section provided (or the section of the `DM`). 5638 5639 Input Parameters: 5640 + dm - The `DM` 5641 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5642 - section - The `PetscSection` to reorder, or `NULL` for the default section 5643 5644 Example: 5645 A typical interpolated single-quad mesh might order points as 5646 .vb 5647 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5648 5649 v4 -- e6 -- v3 5650 | | 5651 e7 c0 e8 5652 | | 5653 v1 -- e5 -- v2 5654 .ve 5655 5656 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5657 dofs in the order of points, e.g., 5658 .vb 5659 c0 -> [0,1,2,3] 5660 v1 -> [4] 5661 ... 5662 e5 -> [8, 9] 5663 .ve 5664 5665 which corresponds to the dofs 5666 .vb 5667 6 10 11 7 5668 13 2 3 15 5669 12 0 1 14 5670 4 8 9 5 5671 .ve 5672 5673 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5674 .vb 5675 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5676 .ve 5677 5678 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5679 .vb 5680 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5681 .ve 5682 5683 Level: developer 5684 5685 Notes: 5686 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5687 degree of the basis. 5688 5689 This is required to run with libCEED. 5690 5691 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5692 @*/ 5693 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5694 { 5695 DMLabel label; 5696 PetscInt dim, depth = -1, eStart = -1, Nf; 5697 PetscBool vertexchart; 5698 5699 PetscFunctionBegin; 5700 PetscCall(DMGetDimension(dm, &dim)); 5701 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5702 if (point < 0) { 5703 PetscInt sStart, sEnd; 5704 5705 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5706 point = sEnd - sStart ? sStart : point; 5707 } 5708 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5709 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5710 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5711 if (depth == 1) { 5712 eStart = point; 5713 } else if (depth == dim) { 5714 const PetscInt *cone; 5715 5716 PetscCall(DMPlexGetCone(dm, point, &cone)); 5717 if (dim == 2) eStart = cone[0]; 5718 else if (dim == 3) { 5719 const PetscInt *cone2; 5720 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5721 eStart = cone2[0]; 5722 } 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); 5723 } 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); 5724 { /* Determine whether the chart covers all points or just vertices. */ 5725 PetscInt pStart, pEnd, cStart, cEnd; 5726 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5727 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5728 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5729 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5730 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5731 } 5732 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5733 for (PetscInt d = 1; d <= dim; d++) { 5734 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5735 PetscInt *perm; 5736 5737 for (f = 0; f < Nf; ++f) { 5738 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5739 size += PetscPowInt(k + 1, d) * Nc; 5740 } 5741 PetscCall(PetscMalloc1(size, &perm)); 5742 for (f = 0; f < Nf; ++f) { 5743 switch (d) { 5744 case 1: 5745 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5746 /* 5747 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5748 We want [ vtx0; edge of length k-1; vtx1 ] 5749 */ 5750 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5751 for (i = 0; i < k - 1; i++) 5752 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5753 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5754 foffset = offset; 5755 break; 5756 case 2: 5757 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5758 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5759 /* The SEM order is 5760 5761 v_lb, {e_b}, v_rb, 5762 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5763 v_lt, reverse {e_t}, v_rt 5764 */ 5765 { 5766 const PetscInt of = 0; 5767 const PetscInt oeb = of + PetscSqr(k - 1); 5768 const PetscInt oer = oeb + (k - 1); 5769 const PetscInt oet = oer + (k - 1); 5770 const PetscInt oel = oet + (k - 1); 5771 const PetscInt ovlb = oel + (k - 1); 5772 const PetscInt ovrb = ovlb + 1; 5773 const PetscInt ovrt = ovrb + 1; 5774 const PetscInt ovlt = ovrt + 1; 5775 PetscInt o; 5776 5777 /* bottom */ 5778 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5779 for (o = oeb; o < oer; ++o) 5780 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5781 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5782 /* middle */ 5783 for (i = 0; i < k - 1; ++i) { 5784 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5785 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5786 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5787 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5788 } 5789 /* top */ 5790 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5791 for (o = oel - 1; o >= oet; --o) 5792 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5793 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5794 foffset = offset; 5795 } 5796 break; 5797 case 3: 5798 /* The original hex closure is 5799 5800 {c, 5801 f_b, f_t, f_f, f_b, f_r, f_l, 5802 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5803 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5804 */ 5805 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5806 /* The SEM order is 5807 Bottom Slice 5808 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5809 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5810 v_blb, {e_bb}, v_brb, 5811 5812 Middle Slice (j) 5813 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5814 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5815 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5816 5817 Top Slice 5818 v_tlf, {e_tf}, v_trf, 5819 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5820 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5821 */ 5822 { 5823 const PetscInt oc = 0; 5824 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5825 const PetscInt oft = ofb + PetscSqr(k - 1); 5826 const PetscInt off = oft + PetscSqr(k - 1); 5827 const PetscInt ofk = off + PetscSqr(k - 1); 5828 const PetscInt ofr = ofk + PetscSqr(k - 1); 5829 const PetscInt ofl = ofr + PetscSqr(k - 1); 5830 const PetscInt oebl = ofl + PetscSqr(k - 1); 5831 const PetscInt oebb = oebl + (k - 1); 5832 const PetscInt oebr = oebb + (k - 1); 5833 const PetscInt oebf = oebr + (k - 1); 5834 const PetscInt oetf = oebf + (k - 1); 5835 const PetscInt oetr = oetf + (k - 1); 5836 const PetscInt oetb = oetr + (k - 1); 5837 const PetscInt oetl = oetb + (k - 1); 5838 const PetscInt oerf = oetl + (k - 1); 5839 const PetscInt oelf = oerf + (k - 1); 5840 const PetscInt oelb = oelf + (k - 1); 5841 const PetscInt oerb = oelb + (k - 1); 5842 const PetscInt ovblf = oerb + (k - 1); 5843 const PetscInt ovblb = ovblf + 1; 5844 const PetscInt ovbrb = ovblb + 1; 5845 const PetscInt ovbrf = ovbrb + 1; 5846 const PetscInt ovtlf = ovbrf + 1; 5847 const PetscInt ovtrf = ovtlf + 1; 5848 const PetscInt ovtrb = ovtrf + 1; 5849 const PetscInt ovtlb = ovtrb + 1; 5850 PetscInt o, n; 5851 5852 /* Bottom Slice */ 5853 /* bottom */ 5854 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5855 for (o = oetf - 1; o >= oebf; --o) 5856 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5857 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5858 /* middle */ 5859 for (i = 0; i < k - 1; ++i) { 5860 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5861 for (n = 0; n < k - 1; ++n) { 5862 o = ofb + n * (k - 1) + i; 5863 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5864 } 5865 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5866 } 5867 /* top */ 5868 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5869 for (o = oebb; o < oebr; ++o) 5870 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5871 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5872 5873 /* Middle Slice */ 5874 for (j = 0; j < k - 1; ++j) { 5875 /* bottom */ 5876 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5877 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5878 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5879 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5880 /* middle */ 5881 for (i = 0; i < k - 1; ++i) { 5882 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5883 for (n = 0; n < k - 1; ++n) 5884 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5885 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5886 } 5887 /* top */ 5888 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5889 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5890 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5891 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5892 } 5893 5894 /* Top Slice */ 5895 /* bottom */ 5896 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5897 for (o = oetf; o < oetr; ++o) 5898 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5899 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5900 /* middle */ 5901 for (i = 0; i < k - 1; ++i) { 5902 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5903 for (n = 0; n < k - 1; ++n) 5904 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5905 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5906 } 5907 /* top */ 5908 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5909 for (o = oetl - 1; o >= oetb; --o) 5910 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5911 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5912 5913 foffset = offset; 5914 } 5915 break; 5916 default: 5917 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5918 } 5919 } 5920 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5921 /* Check permutation */ 5922 { 5923 PetscInt *check; 5924 5925 PetscCall(PetscMalloc1(size, &check)); 5926 for (i = 0; i < size; ++i) { 5927 check[i] = -1; 5928 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5929 } 5930 for (i = 0; i < size; ++i) check[perm[i]] = i; 5931 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5932 PetscCall(PetscFree(check)); 5933 } 5934 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5935 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5936 PetscInt *loc_perm; 5937 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5938 for (PetscInt i = 0; i < size; i++) { 5939 loc_perm[i] = perm[i]; 5940 loc_perm[size + i] = size + perm[i]; 5941 } 5942 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5943 } 5944 } 5945 PetscFunctionReturn(PETSC_SUCCESS); 5946 } 5947 5948 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5949 { 5950 PetscDS prob; 5951 PetscInt depth, Nf, h; 5952 DMLabel label; 5953 5954 PetscFunctionBeginHot; 5955 PetscCall(DMGetDS(dm, &prob)); 5956 Nf = prob->Nf; 5957 label = dm->depthLabel; 5958 *dspace = NULL; 5959 if (field < Nf) { 5960 PetscObject disc = prob->disc[field]; 5961 5962 if (disc->classid == PETSCFE_CLASSID) { 5963 PetscDualSpace dsp; 5964 5965 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5966 PetscCall(DMLabelGetNumValues(label, &depth)); 5967 PetscCall(DMLabelGetValue(label, point, &h)); 5968 h = depth - 1 - h; 5969 if (h) { 5970 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5971 } else { 5972 *dspace = dsp; 5973 } 5974 } 5975 } 5976 PetscFunctionReturn(PETSC_SUCCESS); 5977 } 5978 5979 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5980 { 5981 PetscScalar *array; 5982 const PetscScalar *vArray; 5983 const PetscInt *cone, *coneO; 5984 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5985 5986 PetscFunctionBeginHot; 5987 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5988 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5989 PetscCall(DMPlexGetCone(dm, point, &cone)); 5990 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5991 if (!values || !*values) { 5992 if ((point >= pStart) && (point < pEnd)) { 5993 PetscInt dof; 5994 5995 PetscCall(PetscSectionGetDof(section, point, &dof)); 5996 size += dof; 5997 } 5998 for (p = 0; p < numPoints; ++p) { 5999 const PetscInt cp = cone[p]; 6000 PetscInt dof; 6001 6002 if ((cp < pStart) || (cp >= pEnd)) continue; 6003 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6004 size += dof; 6005 } 6006 if (!values) { 6007 if (csize) *csize = size; 6008 PetscFunctionReturn(PETSC_SUCCESS); 6009 } 6010 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6011 } else { 6012 array = *values; 6013 } 6014 size = 0; 6015 PetscCall(VecGetArrayRead(v, &vArray)); 6016 if ((point >= pStart) && (point < pEnd)) { 6017 PetscInt dof, off, d; 6018 const PetscScalar *varr; 6019 6020 PetscCall(PetscSectionGetDof(section, point, &dof)); 6021 PetscCall(PetscSectionGetOffset(section, point, &off)); 6022 varr = &vArray[off]; 6023 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6024 size += dof; 6025 } 6026 for (p = 0; p < numPoints; ++p) { 6027 const PetscInt cp = cone[p]; 6028 PetscInt o = coneO[p]; 6029 PetscInt dof, off, d; 6030 const PetscScalar *varr; 6031 6032 if ((cp < pStart) || (cp >= pEnd)) continue; 6033 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6034 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6035 varr = &vArray[off]; 6036 if (o >= 0) { 6037 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6038 } else { 6039 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6040 } 6041 size += dof; 6042 } 6043 PetscCall(VecRestoreArrayRead(v, &vArray)); 6044 if (!*values) { 6045 if (csize) *csize = size; 6046 *values = array; 6047 } else { 6048 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6049 *csize = size; 6050 } 6051 PetscFunctionReturn(PETSC_SUCCESS); 6052 } 6053 6054 /* Compress out points not in the section */ 6055 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6056 { 6057 const PetscInt np = *numPoints; 6058 PetscInt pStart, pEnd, p, q; 6059 6060 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6061 for (p = 0, q = 0; p < np; ++p) { 6062 const PetscInt r = points[p * 2]; 6063 if ((r >= pStart) && (r < pEnd)) { 6064 points[q * 2] = r; 6065 points[q * 2 + 1] = points[p * 2 + 1]; 6066 ++q; 6067 } 6068 } 6069 *numPoints = q; 6070 return PETSC_SUCCESS; 6071 } 6072 6073 /* Compressed closure does not apply closure permutation */ 6074 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6075 { 6076 const PetscInt *cla = NULL; 6077 PetscInt np, *pts = NULL; 6078 6079 PetscFunctionBeginHot; 6080 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6081 if (!ornt && *clPoints) { 6082 PetscInt dof, off; 6083 6084 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6085 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6086 PetscCall(ISGetIndices(*clPoints, &cla)); 6087 np = dof / 2; 6088 pts = (PetscInt *)&cla[off]; 6089 } else { 6090 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6091 PetscCall(CompressPoints_Private(section, &np, pts)); 6092 } 6093 *numPoints = np; 6094 *points = pts; 6095 *clp = cla; 6096 PetscFunctionReturn(PETSC_SUCCESS); 6097 } 6098 6099 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6100 { 6101 PetscFunctionBeginHot; 6102 if (!*clPoints) { 6103 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6104 } else { 6105 PetscCall(ISRestoreIndices(*clPoints, clp)); 6106 } 6107 *numPoints = 0; 6108 *points = NULL; 6109 *clSec = NULL; 6110 *clPoints = NULL; 6111 *clp = NULL; 6112 PetscFunctionReturn(PETSC_SUCCESS); 6113 } 6114 6115 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6116 { 6117 PetscInt offset = 0, p; 6118 const PetscInt **perms = NULL; 6119 const PetscScalar **flips = NULL; 6120 6121 PetscFunctionBeginHot; 6122 *size = 0; 6123 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6124 for (p = 0; p < numPoints; p++) { 6125 const PetscInt point = points[2 * p]; 6126 const PetscInt *perm = perms ? perms[p] : NULL; 6127 const PetscScalar *flip = flips ? flips[p] : NULL; 6128 PetscInt dof, off, d; 6129 const PetscScalar *varr; 6130 6131 PetscCall(PetscSectionGetDof(section, point, &dof)); 6132 PetscCall(PetscSectionGetOffset(section, point, &off)); 6133 varr = &vArray[off]; 6134 if (clperm) { 6135 if (perm) { 6136 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6137 } else { 6138 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6139 } 6140 if (flip) { 6141 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6142 } 6143 } else { 6144 if (perm) { 6145 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6146 } else { 6147 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6148 } 6149 if (flip) { 6150 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6151 } 6152 } 6153 offset += dof; 6154 } 6155 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6156 *size = offset; 6157 PetscFunctionReturn(PETSC_SUCCESS); 6158 } 6159 6160 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[]) 6161 { 6162 PetscInt offset = 0, f; 6163 6164 PetscFunctionBeginHot; 6165 *size = 0; 6166 for (f = 0; f < numFields; ++f) { 6167 PetscInt p; 6168 const PetscInt **perms = NULL; 6169 const PetscScalar **flips = NULL; 6170 6171 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6172 for (p = 0; p < numPoints; p++) { 6173 const PetscInt point = points[2 * p]; 6174 PetscInt fdof, foff, b; 6175 const PetscScalar *varr; 6176 const PetscInt *perm = perms ? perms[p] : NULL; 6177 const PetscScalar *flip = flips ? flips[p] : NULL; 6178 6179 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6180 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6181 varr = &vArray[foff]; 6182 if (clperm) { 6183 if (perm) { 6184 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6185 } else { 6186 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6187 } 6188 if (flip) { 6189 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6190 } 6191 } else { 6192 if (perm) { 6193 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6194 } else { 6195 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6196 } 6197 if (flip) { 6198 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6199 } 6200 } 6201 offset += fdof; 6202 } 6203 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6204 } 6205 *size = offset; 6206 PetscFunctionReturn(PETSC_SUCCESS); 6207 } 6208 6209 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6210 { 6211 PetscSection clSection; 6212 IS clPoints; 6213 PetscInt *points = NULL; 6214 const PetscInt *clp, *perm = NULL; 6215 PetscInt depth, numFields, numPoints, asize; 6216 6217 PetscFunctionBeginHot; 6218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6219 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6220 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6221 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6222 PetscCall(DMPlexGetDepth(dm, &depth)); 6223 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6224 if (depth == 1 && numFields < 2) { 6225 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6226 PetscFunctionReturn(PETSC_SUCCESS); 6227 } 6228 /* Get points */ 6229 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6230 /* Get sizes */ 6231 asize = 0; 6232 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6233 PetscInt dof; 6234 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6235 asize += dof; 6236 } 6237 if (values) { 6238 const PetscScalar *vArray; 6239 PetscInt size; 6240 6241 if (*values) { 6242 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); 6243 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6244 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6245 PetscCall(VecGetArrayRead(v, &vArray)); 6246 /* Get values */ 6247 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6248 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6249 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6250 /* Cleanup array */ 6251 PetscCall(VecRestoreArrayRead(v, &vArray)); 6252 } 6253 if (csize) *csize = asize; 6254 /* Cleanup points */ 6255 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6256 PetscFunctionReturn(PETSC_SUCCESS); 6257 } 6258 6259 /*@C 6260 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6261 6262 Not collective 6263 6264 Input Parameters: 6265 + dm - The `DM` 6266 . section - The section describing the layout in `v`, or `NULL` to use the default section 6267 . v - The local vector 6268 - point - The point in the `DM` 6269 6270 Input/Output Parameters: 6271 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6272 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6273 if the user provided `NULL`, it is a borrowed array and should not be freed 6274 6275 Level: intermediate 6276 6277 Notes: 6278 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6279 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6280 assembly function, and a user may already have allocated storage for this operation. 6281 6282 A typical use could be 6283 .vb 6284 values = NULL; 6285 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6286 for (cl = 0; cl < clSize; ++cl) { 6287 <Compute on closure> 6288 } 6289 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6290 .ve 6291 or 6292 .vb 6293 PetscMalloc1(clMaxSize, &values); 6294 for (p = pStart; p < pEnd; ++p) { 6295 clSize = clMaxSize; 6296 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6297 for (cl = 0; cl < clSize; ++cl) { 6298 <Compute on closure> 6299 } 6300 } 6301 PetscFree(values); 6302 .ve 6303 6304 Fortran Notes: 6305 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6306 6307 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6308 @*/ 6309 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6310 { 6311 PetscFunctionBeginHot; 6312 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6313 PetscFunctionReturn(PETSC_SUCCESS); 6314 } 6315 6316 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6317 { 6318 DMLabel depthLabel; 6319 PetscSection clSection; 6320 IS clPoints; 6321 PetscScalar *array; 6322 const PetscScalar *vArray; 6323 PetscInt *points = NULL; 6324 const PetscInt *clp, *perm = NULL; 6325 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6326 6327 PetscFunctionBeginHot; 6328 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6329 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6330 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6331 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6332 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6333 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6334 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6335 if (mdepth == 1 && numFields < 2) { 6336 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6337 PetscFunctionReturn(PETSC_SUCCESS); 6338 } 6339 /* Get points */ 6340 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6341 for (clsize = 0, p = 0; p < Np; p++) { 6342 PetscInt dof; 6343 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6344 clsize += dof; 6345 } 6346 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6347 /* Filter points */ 6348 for (p = 0; p < numPoints * 2; p += 2) { 6349 PetscInt dep; 6350 6351 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6352 if (dep != depth) continue; 6353 points[Np * 2 + 0] = points[p]; 6354 points[Np * 2 + 1] = points[p + 1]; 6355 ++Np; 6356 } 6357 /* Get array */ 6358 if (!values || !*values) { 6359 PetscInt asize = 0, dof; 6360 6361 for (p = 0; p < Np * 2; p += 2) { 6362 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6363 asize += dof; 6364 } 6365 if (!values) { 6366 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6367 if (csize) *csize = asize; 6368 PetscFunctionReturn(PETSC_SUCCESS); 6369 } 6370 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6371 } else { 6372 array = *values; 6373 } 6374 PetscCall(VecGetArrayRead(v, &vArray)); 6375 /* Get values */ 6376 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6377 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6378 /* Cleanup points */ 6379 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6380 /* Cleanup array */ 6381 PetscCall(VecRestoreArrayRead(v, &vArray)); 6382 if (!*values) { 6383 if (csize) *csize = size; 6384 *values = array; 6385 } else { 6386 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6387 *csize = size; 6388 } 6389 PetscFunctionReturn(PETSC_SUCCESS); 6390 } 6391 6392 /*@C 6393 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6394 6395 Not collective 6396 6397 Input Parameters: 6398 + dm - The `DM` 6399 . section - The section describing the layout in `v`, or `NULL` to use the default section 6400 . v - The local vector 6401 . point - The point in the `DM` 6402 . csize - The number of values in the closure, or `NULL` 6403 - values - The array of values, which is a borrowed array and should not be freed 6404 6405 Level: intermediate 6406 6407 Note: 6408 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6409 6410 Fortran Notes: 6411 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6412 6413 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6414 @*/ 6415 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6416 { 6417 PetscInt size = 0; 6418 6419 PetscFunctionBegin; 6420 /* Should work without recalculating size */ 6421 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6422 *values = NULL; 6423 PetscFunctionReturn(PETSC_SUCCESS); 6424 } 6425 6426 static inline void add(PetscScalar *x, PetscScalar y) 6427 { 6428 *x += y; 6429 } 6430 static inline void insert(PetscScalar *x, PetscScalar y) 6431 { 6432 *x = y; 6433 } 6434 6435 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[]) 6436 { 6437 PetscInt cdof; /* The number of constraints on this point */ 6438 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6439 PetscScalar *a; 6440 PetscInt off, cind = 0, k; 6441 6442 PetscFunctionBegin; 6443 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6444 PetscCall(PetscSectionGetOffset(section, point, &off)); 6445 a = &array[off]; 6446 if (!cdof || setBC) { 6447 if (clperm) { 6448 if (perm) { 6449 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6450 } else { 6451 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6452 } 6453 } else { 6454 if (perm) { 6455 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6456 } else { 6457 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6458 } 6459 } 6460 } else { 6461 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6462 if (clperm) { 6463 if (perm) { 6464 for (k = 0; k < dof; ++k) { 6465 if ((cind < cdof) && (k == cdofs[cind])) { 6466 ++cind; 6467 continue; 6468 } 6469 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6470 } 6471 } else { 6472 for (k = 0; k < dof; ++k) { 6473 if ((cind < cdof) && (k == cdofs[cind])) { 6474 ++cind; 6475 continue; 6476 } 6477 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6478 } 6479 } 6480 } else { 6481 if (perm) { 6482 for (k = 0; k < dof; ++k) { 6483 if ((cind < cdof) && (k == cdofs[cind])) { 6484 ++cind; 6485 continue; 6486 } 6487 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6488 } 6489 } else { 6490 for (k = 0; k < dof; ++k) { 6491 if ((cind < cdof) && (k == cdofs[cind])) { 6492 ++cind; 6493 continue; 6494 } 6495 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6496 } 6497 } 6498 } 6499 } 6500 PetscFunctionReturn(PETSC_SUCCESS); 6501 } 6502 6503 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[]) 6504 { 6505 PetscInt cdof; /* The number of constraints on this point */ 6506 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6507 PetscScalar *a; 6508 PetscInt off, cind = 0, k; 6509 6510 PetscFunctionBegin; 6511 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6512 PetscCall(PetscSectionGetOffset(section, point, &off)); 6513 a = &array[off]; 6514 if (cdof) { 6515 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6516 if (clperm) { 6517 if (perm) { 6518 for (k = 0; k < dof; ++k) { 6519 if ((cind < cdof) && (k == cdofs[cind])) { 6520 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6521 cind++; 6522 } 6523 } 6524 } else { 6525 for (k = 0; k < dof; ++k) { 6526 if ((cind < cdof) && (k == cdofs[cind])) { 6527 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6528 cind++; 6529 } 6530 } 6531 } 6532 } else { 6533 if (perm) { 6534 for (k = 0; k < dof; ++k) { 6535 if ((cind < cdof) && (k == cdofs[cind])) { 6536 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6537 cind++; 6538 } 6539 } 6540 } else { 6541 for (k = 0; k < dof; ++k) { 6542 if ((cind < cdof) && (k == cdofs[cind])) { 6543 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6544 cind++; 6545 } 6546 } 6547 } 6548 } 6549 } 6550 PetscFunctionReturn(PETSC_SUCCESS); 6551 } 6552 6553 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[]) 6554 { 6555 PetscScalar *a; 6556 PetscInt fdof, foff, fcdof, foffset = *offset; 6557 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6558 PetscInt cind = 0, b; 6559 6560 PetscFunctionBegin; 6561 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6562 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6563 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6564 a = &array[foff]; 6565 if (!fcdof || setBC) { 6566 if (clperm) { 6567 if (perm) { 6568 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6569 } else { 6570 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6571 } 6572 } else { 6573 if (perm) { 6574 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6575 } else { 6576 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6577 } 6578 } 6579 } else { 6580 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6581 if (clperm) { 6582 if (perm) { 6583 for (b = 0; b < fdof; b++) { 6584 if ((cind < fcdof) && (b == fcdofs[cind])) { 6585 ++cind; 6586 continue; 6587 } 6588 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6589 } 6590 } else { 6591 for (b = 0; b < fdof; b++) { 6592 if ((cind < fcdof) && (b == fcdofs[cind])) { 6593 ++cind; 6594 continue; 6595 } 6596 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6597 } 6598 } 6599 } else { 6600 if (perm) { 6601 for (b = 0; b < fdof; b++) { 6602 if ((cind < fcdof) && (b == fcdofs[cind])) { 6603 ++cind; 6604 continue; 6605 } 6606 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6607 } 6608 } else { 6609 for (b = 0; b < fdof; b++) { 6610 if ((cind < fcdof) && (b == fcdofs[cind])) { 6611 ++cind; 6612 continue; 6613 } 6614 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6615 } 6616 } 6617 } 6618 } 6619 *offset += fdof; 6620 PetscFunctionReturn(PETSC_SUCCESS); 6621 } 6622 6623 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[]) 6624 { 6625 PetscScalar *a; 6626 PetscInt fdof, foff, fcdof, foffset = *offset; 6627 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6628 PetscInt Nc, cind = 0, ncind = 0, b; 6629 PetscBool ncSet, fcSet; 6630 6631 PetscFunctionBegin; 6632 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6633 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6634 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6635 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6636 a = &array[foff]; 6637 if (fcdof) { 6638 /* We just override fcdof and fcdofs with Ncc and comps */ 6639 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6640 if (clperm) { 6641 if (perm) { 6642 if (comps) { 6643 for (b = 0; b < fdof; b++) { 6644 ncSet = fcSet = PETSC_FALSE; 6645 if (b % Nc == comps[ncind]) { 6646 ncind = (ncind + 1) % Ncc; 6647 ncSet = PETSC_TRUE; 6648 } 6649 if ((cind < fcdof) && (b == fcdofs[cind])) { 6650 ++cind; 6651 fcSet = PETSC_TRUE; 6652 } 6653 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6654 } 6655 } else { 6656 for (b = 0; b < fdof; b++) { 6657 if ((cind < fcdof) && (b == fcdofs[cind])) { 6658 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6659 ++cind; 6660 } 6661 } 6662 } 6663 } else { 6664 if (comps) { 6665 for (b = 0; b < fdof; b++) { 6666 ncSet = fcSet = PETSC_FALSE; 6667 if (b % Nc == comps[ncind]) { 6668 ncind = (ncind + 1) % Ncc; 6669 ncSet = PETSC_TRUE; 6670 } 6671 if ((cind < fcdof) && (b == fcdofs[cind])) { 6672 ++cind; 6673 fcSet = PETSC_TRUE; 6674 } 6675 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6676 } 6677 } else { 6678 for (b = 0; b < fdof; b++) { 6679 if ((cind < fcdof) && (b == fcdofs[cind])) { 6680 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6681 ++cind; 6682 } 6683 } 6684 } 6685 } 6686 } else { 6687 if (perm) { 6688 if (comps) { 6689 for (b = 0; b < fdof; b++) { 6690 ncSet = fcSet = PETSC_FALSE; 6691 if (b % Nc == comps[ncind]) { 6692 ncind = (ncind + 1) % Ncc; 6693 ncSet = PETSC_TRUE; 6694 } 6695 if ((cind < fcdof) && (b == fcdofs[cind])) { 6696 ++cind; 6697 fcSet = PETSC_TRUE; 6698 } 6699 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6700 } 6701 } else { 6702 for (b = 0; b < fdof; b++) { 6703 if ((cind < fcdof) && (b == fcdofs[cind])) { 6704 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6705 ++cind; 6706 } 6707 } 6708 } 6709 } else { 6710 if (comps) { 6711 for (b = 0; b < fdof; b++) { 6712 ncSet = fcSet = PETSC_FALSE; 6713 if (b % Nc == comps[ncind]) { 6714 ncind = (ncind + 1) % Ncc; 6715 ncSet = PETSC_TRUE; 6716 } 6717 if ((cind < fcdof) && (b == fcdofs[cind])) { 6718 ++cind; 6719 fcSet = PETSC_TRUE; 6720 } 6721 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6722 } 6723 } else { 6724 for (b = 0; b < fdof; b++) { 6725 if ((cind < fcdof) && (b == fcdofs[cind])) { 6726 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6727 ++cind; 6728 } 6729 } 6730 } 6731 } 6732 } 6733 } 6734 *offset += fdof; 6735 PetscFunctionReturn(PETSC_SUCCESS); 6736 } 6737 6738 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6739 { 6740 PetscScalar *array; 6741 const PetscInt *cone, *coneO; 6742 PetscInt pStart, pEnd, p, numPoints, off, dof; 6743 6744 PetscFunctionBeginHot; 6745 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6746 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6747 PetscCall(DMPlexGetCone(dm, point, &cone)); 6748 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6749 PetscCall(VecGetArray(v, &array)); 6750 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6751 const PetscInt cp = !p ? point : cone[p - 1]; 6752 const PetscInt o = !p ? 0 : coneO[p - 1]; 6753 6754 if ((cp < pStart) || (cp >= pEnd)) { 6755 dof = 0; 6756 continue; 6757 } 6758 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6759 /* ADD_VALUES */ 6760 { 6761 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6762 PetscScalar *a; 6763 PetscInt cdof, coff, cind = 0, k; 6764 6765 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6766 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6767 a = &array[coff]; 6768 if (!cdof) { 6769 if (o >= 0) { 6770 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6771 } else { 6772 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6773 } 6774 } else { 6775 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6776 if (o >= 0) { 6777 for (k = 0; k < dof; ++k) { 6778 if ((cind < cdof) && (k == cdofs[cind])) { 6779 ++cind; 6780 continue; 6781 } 6782 a[k] += values[off + k]; 6783 } 6784 } else { 6785 for (k = 0; k < dof; ++k) { 6786 if ((cind < cdof) && (k == cdofs[cind])) { 6787 ++cind; 6788 continue; 6789 } 6790 a[k] += values[off + dof - k - 1]; 6791 } 6792 } 6793 } 6794 } 6795 } 6796 PetscCall(VecRestoreArray(v, &array)); 6797 PetscFunctionReturn(PETSC_SUCCESS); 6798 } 6799 6800 /*@C 6801 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6802 6803 Not collective 6804 6805 Input Parameters: 6806 + dm - The `DM` 6807 . section - The section describing the layout in `v`, or `NULL` to use the default section 6808 . v - The local vector 6809 . point - The point in the `DM` 6810 . values - The array of values 6811 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6812 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6813 6814 Level: intermediate 6815 6816 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6817 @*/ 6818 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6819 { 6820 PetscSection clSection; 6821 IS clPoints; 6822 PetscScalar *array; 6823 PetscInt *points = NULL; 6824 const PetscInt *clp, *clperm = NULL; 6825 PetscInt depth, numFields, numPoints, p, clsize; 6826 6827 PetscFunctionBeginHot; 6828 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6829 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6830 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6831 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6832 PetscCall(DMPlexGetDepth(dm, &depth)); 6833 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6834 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6835 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6836 PetscFunctionReturn(PETSC_SUCCESS); 6837 } 6838 /* Get points */ 6839 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6840 for (clsize = 0, p = 0; p < numPoints; p++) { 6841 PetscInt dof; 6842 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6843 clsize += dof; 6844 } 6845 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6846 /* Get array */ 6847 PetscCall(VecGetArray(v, &array)); 6848 /* Get values */ 6849 if (numFields > 0) { 6850 PetscInt offset = 0, f; 6851 for (f = 0; f < numFields; ++f) { 6852 const PetscInt **perms = NULL; 6853 const PetscScalar **flips = NULL; 6854 6855 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6856 switch (mode) { 6857 case INSERT_VALUES: 6858 for (p = 0; p < numPoints; p++) { 6859 const PetscInt point = points[2 * p]; 6860 const PetscInt *perm = perms ? perms[p] : NULL; 6861 const PetscScalar *flip = flips ? flips[p] : NULL; 6862 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6863 } 6864 break; 6865 case INSERT_ALL_VALUES: 6866 for (p = 0; p < numPoints; p++) { 6867 const PetscInt point = points[2 * p]; 6868 const PetscInt *perm = perms ? perms[p] : NULL; 6869 const PetscScalar *flip = flips ? flips[p] : NULL; 6870 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6871 } 6872 break; 6873 case INSERT_BC_VALUES: 6874 for (p = 0; p < numPoints; p++) { 6875 const PetscInt point = points[2 * p]; 6876 const PetscInt *perm = perms ? perms[p] : NULL; 6877 const PetscScalar *flip = flips ? flips[p] : NULL; 6878 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6879 } 6880 break; 6881 case ADD_VALUES: 6882 for (p = 0; p < numPoints; p++) { 6883 const PetscInt point = points[2 * p]; 6884 const PetscInt *perm = perms ? perms[p] : NULL; 6885 const PetscScalar *flip = flips ? flips[p] : NULL; 6886 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6887 } 6888 break; 6889 case ADD_ALL_VALUES: 6890 for (p = 0; p < numPoints; p++) { 6891 const PetscInt point = points[2 * p]; 6892 const PetscInt *perm = perms ? perms[p] : NULL; 6893 const PetscScalar *flip = flips ? flips[p] : NULL; 6894 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6895 } 6896 break; 6897 case ADD_BC_VALUES: 6898 for (p = 0; p < numPoints; p++) { 6899 const PetscInt point = points[2 * p]; 6900 const PetscInt *perm = perms ? perms[p] : NULL; 6901 const PetscScalar *flip = flips ? flips[p] : NULL; 6902 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6903 } 6904 break; 6905 default: 6906 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6907 } 6908 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6909 } 6910 } else { 6911 PetscInt dof, off; 6912 const PetscInt **perms = NULL; 6913 const PetscScalar **flips = NULL; 6914 6915 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6916 switch (mode) { 6917 case INSERT_VALUES: 6918 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6919 const PetscInt point = points[2 * p]; 6920 const PetscInt *perm = perms ? perms[p] : NULL; 6921 const PetscScalar *flip = flips ? flips[p] : NULL; 6922 PetscCall(PetscSectionGetDof(section, point, &dof)); 6923 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6924 } 6925 break; 6926 case INSERT_ALL_VALUES: 6927 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6928 const PetscInt point = points[2 * p]; 6929 const PetscInt *perm = perms ? perms[p] : NULL; 6930 const PetscScalar *flip = flips ? flips[p] : NULL; 6931 PetscCall(PetscSectionGetDof(section, point, &dof)); 6932 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6933 } 6934 break; 6935 case INSERT_BC_VALUES: 6936 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6937 const PetscInt point = points[2 * p]; 6938 const PetscInt *perm = perms ? perms[p] : NULL; 6939 const PetscScalar *flip = flips ? flips[p] : NULL; 6940 PetscCall(PetscSectionGetDof(section, point, &dof)); 6941 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6942 } 6943 break; 6944 case ADD_VALUES: 6945 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6946 const PetscInt point = points[2 * p]; 6947 const PetscInt *perm = perms ? perms[p] : NULL; 6948 const PetscScalar *flip = flips ? flips[p] : NULL; 6949 PetscCall(PetscSectionGetDof(section, point, &dof)); 6950 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6951 } 6952 break; 6953 case ADD_ALL_VALUES: 6954 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6955 const PetscInt point = points[2 * p]; 6956 const PetscInt *perm = perms ? perms[p] : NULL; 6957 const PetscScalar *flip = flips ? flips[p] : NULL; 6958 PetscCall(PetscSectionGetDof(section, point, &dof)); 6959 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6960 } 6961 break; 6962 case ADD_BC_VALUES: 6963 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6964 const PetscInt point = points[2 * p]; 6965 const PetscInt *perm = perms ? perms[p] : NULL; 6966 const PetscScalar *flip = flips ? flips[p] : NULL; 6967 PetscCall(PetscSectionGetDof(section, point, &dof)); 6968 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6969 } 6970 break; 6971 default: 6972 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6973 } 6974 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6975 } 6976 /* Cleanup points */ 6977 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6978 /* Cleanup array */ 6979 PetscCall(VecRestoreArray(v, &array)); 6980 PetscFunctionReturn(PETSC_SUCCESS); 6981 } 6982 6983 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6984 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6985 { 6986 PetscFunctionBegin; 6987 *contains = PETSC_TRUE; 6988 if (label) { 6989 PetscInt fdof; 6990 6991 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6992 if (!*contains) { 6993 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6994 *offset += fdof; 6995 PetscFunctionReturn(PETSC_SUCCESS); 6996 } 6997 } 6998 PetscFunctionReturn(PETSC_SUCCESS); 6999 } 7000 7001 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7002 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) 7003 { 7004 PetscSection clSection; 7005 IS clPoints; 7006 PetscScalar *array; 7007 PetscInt *points = NULL; 7008 const PetscInt *clp; 7009 PetscInt numFields, numPoints, p; 7010 PetscInt offset = 0, f; 7011 7012 PetscFunctionBeginHot; 7013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7014 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7015 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7016 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7017 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7018 /* Get points */ 7019 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7020 /* Get array */ 7021 PetscCall(VecGetArray(v, &array)); 7022 /* Get values */ 7023 for (f = 0; f < numFields; ++f) { 7024 const PetscInt **perms = NULL; 7025 const PetscScalar **flips = NULL; 7026 PetscBool contains; 7027 7028 if (!fieldActive[f]) { 7029 for (p = 0; p < numPoints * 2; p += 2) { 7030 PetscInt fdof; 7031 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7032 offset += fdof; 7033 } 7034 continue; 7035 } 7036 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7037 switch (mode) { 7038 case INSERT_VALUES: 7039 for (p = 0; p < numPoints; p++) { 7040 const PetscInt point = points[2 * p]; 7041 const PetscInt *perm = perms ? perms[p] : NULL; 7042 const PetscScalar *flip = flips ? flips[p] : NULL; 7043 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7044 if (!contains) continue; 7045 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7046 } 7047 break; 7048 case INSERT_ALL_VALUES: 7049 for (p = 0; p < numPoints; p++) { 7050 const PetscInt point = points[2 * p]; 7051 const PetscInt *perm = perms ? perms[p] : NULL; 7052 const PetscScalar *flip = flips ? flips[p] : NULL; 7053 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7054 if (!contains) continue; 7055 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7056 } 7057 break; 7058 case INSERT_BC_VALUES: 7059 for (p = 0; p < numPoints; p++) { 7060 const PetscInt point = points[2 * p]; 7061 const PetscInt *perm = perms ? perms[p] : NULL; 7062 const PetscScalar *flip = flips ? flips[p] : NULL; 7063 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7064 if (!contains) continue; 7065 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7066 } 7067 break; 7068 case ADD_VALUES: 7069 for (p = 0; p < numPoints; p++) { 7070 const PetscInt point = points[2 * p]; 7071 const PetscInt *perm = perms ? perms[p] : NULL; 7072 const PetscScalar *flip = flips ? flips[p] : NULL; 7073 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7074 if (!contains) continue; 7075 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7076 } 7077 break; 7078 case ADD_ALL_VALUES: 7079 for (p = 0; p < numPoints; p++) { 7080 const PetscInt point = points[2 * p]; 7081 const PetscInt *perm = perms ? perms[p] : NULL; 7082 const PetscScalar *flip = flips ? flips[p] : NULL; 7083 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7084 if (!contains) continue; 7085 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7086 } 7087 break; 7088 default: 7089 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7090 } 7091 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7092 } 7093 /* Cleanup points */ 7094 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7095 /* Cleanup array */ 7096 PetscCall(VecRestoreArray(v, &array)); 7097 PetscFunctionReturn(PETSC_SUCCESS); 7098 } 7099 7100 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7101 { 7102 PetscMPIInt rank; 7103 PetscInt i, j; 7104 7105 PetscFunctionBegin; 7106 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7107 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7108 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7109 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7110 numCIndices = numCIndices ? numCIndices : numRIndices; 7111 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7112 for (i = 0; i < numRIndices; i++) { 7113 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7114 for (j = 0; j < numCIndices; j++) { 7115 #if defined(PETSC_USE_COMPLEX) 7116 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7117 #else 7118 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7119 #endif 7120 } 7121 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7122 } 7123 PetscFunctionReturn(PETSC_SUCCESS); 7124 } 7125 7126 /* 7127 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7128 7129 Input Parameters: 7130 + section - The section for this data layout 7131 . islocal - Is the section (and thus indices being requested) local or global? 7132 . point - The point contributing dofs with these indices 7133 . off - The global offset of this point 7134 . loff - The local offset of each field 7135 . setBC - The flag determining whether to include indices of boundary values 7136 . perm - A permutation of the dofs on this point, or NULL 7137 - indperm - A permutation of the entire indices array, or NULL 7138 7139 Output Parameter: 7140 . indices - Indices for dofs on this point 7141 7142 Level: developer 7143 7144 Note: The indices could be local or global, depending on the value of 'off'. 7145 */ 7146 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7147 { 7148 PetscInt dof; /* The number of unknowns on this point */ 7149 PetscInt cdof; /* The number of constraints on this point */ 7150 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7151 PetscInt cind = 0, k; 7152 7153 PetscFunctionBegin; 7154 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7155 PetscCall(PetscSectionGetDof(section, point, &dof)); 7156 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7157 if (!cdof || setBC) { 7158 for (k = 0; k < dof; ++k) { 7159 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7160 const PetscInt ind = indperm ? indperm[preind] : preind; 7161 7162 indices[ind] = off + k; 7163 } 7164 } else { 7165 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7166 for (k = 0; k < dof; ++k) { 7167 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7168 const PetscInt ind = indperm ? indperm[preind] : preind; 7169 7170 if ((cind < cdof) && (k == cdofs[cind])) { 7171 /* Insert check for returning constrained indices */ 7172 indices[ind] = -(off + k + 1); 7173 ++cind; 7174 } else { 7175 indices[ind] = off + k - (islocal ? 0 : cind); 7176 } 7177 } 7178 } 7179 *loff += dof; 7180 PetscFunctionReturn(PETSC_SUCCESS); 7181 } 7182 7183 /* 7184 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7185 7186 Input Parameters: 7187 + section - a section (global or local) 7188 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7189 . point - point within section 7190 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7191 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7192 . setBC - identify constrained (boundary condition) points via involution. 7193 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7194 . permsoff - offset 7195 - indperm - index permutation 7196 7197 Output Parameter: 7198 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7199 . indices - array to hold indices (as defined by section) of each dof associated with point 7200 7201 Notes: 7202 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7203 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7204 in the local vector. 7205 7206 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7207 significant). It is invalid to call with a global section and setBC=true. 7208 7209 Developer Note: 7210 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7211 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7212 offset could be obtained from the section instead of passing it explicitly as we do now. 7213 7214 Example: 7215 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7216 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7217 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7218 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. 7219 7220 Level: developer 7221 */ 7222 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[]) 7223 { 7224 PetscInt numFields, foff, f; 7225 7226 PetscFunctionBegin; 7227 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7228 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7229 for (f = 0, foff = 0; f < numFields; ++f) { 7230 PetscInt fdof, cfdof; 7231 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7232 PetscInt cind = 0, b; 7233 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7234 7235 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7236 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7237 if (!cfdof || setBC) { 7238 for (b = 0; b < fdof; ++b) { 7239 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7240 const PetscInt ind = indperm ? indperm[preind] : preind; 7241 7242 indices[ind] = off + foff + b; 7243 } 7244 } else { 7245 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7246 for (b = 0; b < fdof; ++b) { 7247 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7248 const PetscInt ind = indperm ? indperm[preind] : preind; 7249 7250 if ((cind < cfdof) && (b == fcdofs[cind])) { 7251 indices[ind] = -(off + foff + b + 1); 7252 ++cind; 7253 } else { 7254 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7255 } 7256 } 7257 } 7258 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7259 foffs[f] += fdof; 7260 } 7261 PetscFunctionReturn(PETSC_SUCCESS); 7262 } 7263 7264 /* 7265 This version believes the globalSection offsets for each field, rather than just the point offset 7266 7267 . foffs - The offset into 'indices' for each field, since it is segregated by field 7268 7269 Notes: 7270 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7271 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7272 */ 7273 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7274 { 7275 PetscInt numFields, foff, f; 7276 7277 PetscFunctionBegin; 7278 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7279 for (f = 0; f < numFields; ++f) { 7280 PetscInt fdof, cfdof; 7281 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7282 PetscInt cind = 0, b; 7283 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7284 7285 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7286 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7287 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7288 if (!cfdof) { 7289 for (b = 0; b < fdof; ++b) { 7290 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7291 const PetscInt ind = indperm ? indperm[preind] : preind; 7292 7293 indices[ind] = foff + b; 7294 } 7295 } else { 7296 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7297 for (b = 0; b < fdof; ++b) { 7298 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7299 const PetscInt ind = indperm ? indperm[preind] : preind; 7300 7301 if ((cind < cfdof) && (b == fcdofs[cind])) { 7302 indices[ind] = -(foff + b + 1); 7303 ++cind; 7304 } else { 7305 indices[ind] = foff + b - cind; 7306 } 7307 } 7308 } 7309 foffs[f] += fdof; 7310 } 7311 PetscFunctionReturn(PETSC_SUCCESS); 7312 } 7313 7314 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) 7315 { 7316 Mat cMat; 7317 PetscSection aSec, cSec; 7318 IS aIS; 7319 PetscInt aStart = -1, aEnd = -1; 7320 const PetscInt *anchors; 7321 PetscInt numFields, f, p, q, newP = 0; 7322 PetscInt newNumPoints = 0, newNumIndices = 0; 7323 PetscInt *newPoints, *indices, *newIndices; 7324 PetscInt maxAnchor, maxDof; 7325 PetscInt newOffsets[32]; 7326 PetscInt *pointMatOffsets[32]; 7327 PetscInt *newPointOffsets[32]; 7328 PetscScalar *pointMat[32]; 7329 PetscScalar *newValues = NULL, *tmpValues; 7330 PetscBool anyConstrained = PETSC_FALSE; 7331 7332 PetscFunctionBegin; 7333 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7334 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7335 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7336 7337 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7338 /* if there are point-to-point constraints */ 7339 if (aSec) { 7340 PetscCall(PetscArrayzero(newOffsets, 32)); 7341 PetscCall(ISGetIndices(aIS, &anchors)); 7342 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7343 /* figure out how many points are going to be in the new element matrix 7344 * (we allow double counting, because it's all just going to be summed 7345 * into the global matrix anyway) */ 7346 for (p = 0; p < 2 * numPoints; p += 2) { 7347 PetscInt b = points[p]; 7348 PetscInt bDof = 0, bSecDof; 7349 7350 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7351 if (!bSecDof) continue; 7352 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7353 if (bDof) { 7354 /* this point is constrained */ 7355 /* it is going to be replaced by its anchors */ 7356 PetscInt bOff, q; 7357 7358 anyConstrained = PETSC_TRUE; 7359 newNumPoints += bDof; 7360 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7361 for (q = 0; q < bDof; q++) { 7362 PetscInt a = anchors[bOff + q]; 7363 PetscInt aDof; 7364 7365 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7366 newNumIndices += aDof; 7367 for (f = 0; f < numFields; ++f) { 7368 PetscInt fDof; 7369 7370 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7371 newOffsets[f + 1] += fDof; 7372 } 7373 } 7374 } else { 7375 /* this point is not constrained */ 7376 newNumPoints++; 7377 newNumIndices += bSecDof; 7378 for (f = 0; f < numFields; ++f) { 7379 PetscInt fDof; 7380 7381 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7382 newOffsets[f + 1] += fDof; 7383 } 7384 } 7385 } 7386 } 7387 if (!anyConstrained) { 7388 if (outNumPoints) *outNumPoints = 0; 7389 if (outNumIndices) *outNumIndices = 0; 7390 if (outPoints) *outPoints = NULL; 7391 if (outValues) *outValues = NULL; 7392 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7393 PetscFunctionReturn(PETSC_SUCCESS); 7394 } 7395 7396 if (outNumPoints) *outNumPoints = newNumPoints; 7397 if (outNumIndices) *outNumIndices = newNumIndices; 7398 7399 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7400 7401 if (!outPoints && !outValues) { 7402 if (offsets) { 7403 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7404 } 7405 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7406 PetscFunctionReturn(PETSC_SUCCESS); 7407 } 7408 7409 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7410 7411 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7412 7413 /* workspaces */ 7414 if (numFields) { 7415 for (f = 0; f < numFields; f++) { 7416 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7417 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7418 } 7419 } else { 7420 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7421 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7422 } 7423 7424 /* get workspaces for the point-to-point matrices */ 7425 if (numFields) { 7426 PetscInt totalOffset, totalMatOffset; 7427 7428 for (p = 0; p < numPoints; p++) { 7429 PetscInt b = points[2 * p]; 7430 PetscInt bDof = 0, bSecDof; 7431 7432 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7433 if (!bSecDof) { 7434 for (f = 0; f < numFields; f++) { 7435 newPointOffsets[f][p + 1] = 0; 7436 pointMatOffsets[f][p + 1] = 0; 7437 } 7438 continue; 7439 } 7440 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7441 if (bDof) { 7442 for (f = 0; f < numFields; f++) { 7443 PetscInt fDof, q, bOff, allFDof = 0; 7444 7445 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7446 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7447 for (q = 0; q < bDof; q++) { 7448 PetscInt a = anchors[bOff + q]; 7449 PetscInt aFDof; 7450 7451 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7452 allFDof += aFDof; 7453 } 7454 newPointOffsets[f][p + 1] = allFDof; 7455 pointMatOffsets[f][p + 1] = fDof * allFDof; 7456 } 7457 } else { 7458 for (f = 0; f < numFields; f++) { 7459 PetscInt fDof; 7460 7461 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7462 newPointOffsets[f][p + 1] = fDof; 7463 pointMatOffsets[f][p + 1] = 0; 7464 } 7465 } 7466 } 7467 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7468 newPointOffsets[f][0] = totalOffset; 7469 pointMatOffsets[f][0] = totalMatOffset; 7470 for (p = 0; p < numPoints; p++) { 7471 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7472 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7473 } 7474 totalOffset = newPointOffsets[f][numPoints]; 7475 totalMatOffset = pointMatOffsets[f][numPoints]; 7476 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7477 } 7478 } else { 7479 for (p = 0; p < numPoints; p++) { 7480 PetscInt b = points[2 * p]; 7481 PetscInt bDof = 0, bSecDof; 7482 7483 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7484 if (!bSecDof) { 7485 newPointOffsets[0][p + 1] = 0; 7486 pointMatOffsets[0][p + 1] = 0; 7487 continue; 7488 } 7489 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7490 if (bDof) { 7491 PetscInt bOff, q, allDof = 0; 7492 7493 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7494 for (q = 0; q < bDof; q++) { 7495 PetscInt a = anchors[bOff + q], aDof; 7496 7497 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7498 allDof += aDof; 7499 } 7500 newPointOffsets[0][p + 1] = allDof; 7501 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7502 } else { 7503 newPointOffsets[0][p + 1] = bSecDof; 7504 pointMatOffsets[0][p + 1] = 0; 7505 } 7506 } 7507 newPointOffsets[0][0] = 0; 7508 pointMatOffsets[0][0] = 0; 7509 for (p = 0; p < numPoints; p++) { 7510 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7511 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7512 } 7513 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7514 } 7515 7516 /* output arrays */ 7517 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7518 7519 /* get the point-to-point matrices; construct newPoints */ 7520 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7521 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7522 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7523 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7524 if (numFields) { 7525 for (p = 0, newP = 0; p < numPoints; p++) { 7526 PetscInt b = points[2 * p]; 7527 PetscInt o = points[2 * p + 1]; 7528 PetscInt bDof = 0, bSecDof; 7529 7530 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7531 if (!bSecDof) continue; 7532 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7533 if (bDof) { 7534 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7535 7536 fStart[0] = 0; 7537 fEnd[0] = 0; 7538 for (f = 0; f < numFields; f++) { 7539 PetscInt fDof; 7540 7541 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7542 fStart[f + 1] = fStart[f] + fDof; 7543 fEnd[f + 1] = fStart[f + 1]; 7544 } 7545 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7546 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7547 7548 fAnchorStart[0] = 0; 7549 fAnchorEnd[0] = 0; 7550 for (f = 0; f < numFields; f++) { 7551 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7552 7553 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7554 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7555 } 7556 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7557 for (q = 0; q < bDof; q++) { 7558 PetscInt a = anchors[bOff + q], aOff; 7559 7560 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7561 newPoints[2 * (newP + q)] = a; 7562 newPoints[2 * (newP + q) + 1] = 0; 7563 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7564 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7565 } 7566 newP += bDof; 7567 7568 if (outValues) { 7569 /* get the point-to-point submatrix */ 7570 for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p])); 7571 } 7572 } else { 7573 newPoints[2 * newP] = b; 7574 newPoints[2 * newP + 1] = o; 7575 newP++; 7576 } 7577 } 7578 } else { 7579 for (p = 0; p < numPoints; p++) { 7580 PetscInt b = points[2 * p]; 7581 PetscInt o = points[2 * p + 1]; 7582 PetscInt bDof = 0, bSecDof; 7583 7584 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7585 if (!bSecDof) continue; 7586 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7587 if (bDof) { 7588 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7589 7590 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7591 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7592 7593 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7594 for (q = 0; q < bDof; q++) { 7595 PetscInt a = anchors[bOff + q], aOff; 7596 7597 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7598 7599 newPoints[2 * (newP + q)] = a; 7600 newPoints[2 * (newP + q) + 1] = 0; 7601 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7602 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7603 } 7604 newP += bDof; 7605 7606 /* get the point-to-point submatrix */ 7607 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7608 } else { 7609 newPoints[2 * newP] = b; 7610 newPoints[2 * newP + 1] = o; 7611 newP++; 7612 } 7613 } 7614 } 7615 7616 if (outValues) { 7617 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7618 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7619 /* multiply constraints on the right */ 7620 if (numFields) { 7621 for (f = 0; f < numFields; f++) { 7622 PetscInt oldOff = offsets[f]; 7623 7624 for (p = 0; p < numPoints; p++) { 7625 PetscInt cStart = newPointOffsets[f][p]; 7626 PetscInt b = points[2 * p]; 7627 PetscInt c, r, k; 7628 PetscInt dof; 7629 7630 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7631 if (!dof) continue; 7632 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7633 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7634 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7635 7636 for (r = 0; r < numIndices; r++) { 7637 for (c = 0; c < nCols; c++) { 7638 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7639 } 7640 } 7641 } else { 7642 /* copy this column as is */ 7643 for (r = 0; r < numIndices; r++) { 7644 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7645 } 7646 } 7647 oldOff += dof; 7648 } 7649 } 7650 } else { 7651 PetscInt oldOff = 0; 7652 for (p = 0; p < numPoints; p++) { 7653 PetscInt cStart = newPointOffsets[0][p]; 7654 PetscInt b = points[2 * p]; 7655 PetscInt c, r, k; 7656 PetscInt dof; 7657 7658 PetscCall(PetscSectionGetDof(section, b, &dof)); 7659 if (!dof) continue; 7660 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7661 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7662 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7663 7664 for (r = 0; r < numIndices; r++) { 7665 for (c = 0; c < nCols; c++) { 7666 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7667 } 7668 } 7669 } else { 7670 /* copy this column as is */ 7671 for (r = 0; r < numIndices; r++) { 7672 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7673 } 7674 } 7675 oldOff += dof; 7676 } 7677 } 7678 7679 if (multiplyLeft) { 7680 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7681 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7682 /* multiply constraints transpose on the left */ 7683 if (numFields) { 7684 for (f = 0; f < numFields; f++) { 7685 PetscInt oldOff = offsets[f]; 7686 7687 for (p = 0; p < numPoints; p++) { 7688 PetscInt rStart = newPointOffsets[f][p]; 7689 PetscInt b = points[2 * p]; 7690 PetscInt c, r, k; 7691 PetscInt dof; 7692 7693 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7694 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7695 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7696 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7697 7698 for (r = 0; r < nRows; r++) { 7699 for (c = 0; c < newNumIndices; c++) { 7700 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7701 } 7702 } 7703 } else { 7704 /* copy this row as is */ 7705 for (r = 0; r < dof; r++) { 7706 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7707 } 7708 } 7709 oldOff += dof; 7710 } 7711 } 7712 } else { 7713 PetscInt oldOff = 0; 7714 7715 for (p = 0; p < numPoints; p++) { 7716 PetscInt rStart = newPointOffsets[0][p]; 7717 PetscInt b = points[2 * p]; 7718 PetscInt c, r, k; 7719 PetscInt dof; 7720 7721 PetscCall(PetscSectionGetDof(section, b, &dof)); 7722 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7723 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7724 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7725 7726 for (r = 0; r < nRows; r++) { 7727 for (c = 0; c < newNumIndices; c++) { 7728 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7729 } 7730 } 7731 } else { 7732 /* copy this row as is */ 7733 for (r = 0; r < dof; r++) { 7734 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7735 } 7736 } 7737 oldOff += dof; 7738 } 7739 } 7740 7741 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7742 } else { 7743 newValues = tmpValues; 7744 } 7745 } 7746 7747 /* clean up */ 7748 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7749 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7750 7751 if (numFields) { 7752 for (f = 0; f < numFields; f++) { 7753 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7754 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7755 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7756 } 7757 } else { 7758 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7759 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7760 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7761 } 7762 PetscCall(ISRestoreIndices(aIS, &anchors)); 7763 7764 /* output */ 7765 if (outPoints) { 7766 *outPoints = newPoints; 7767 } else { 7768 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7769 } 7770 if (outValues) *outValues = newValues; 7771 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7772 PetscFunctionReturn(PETSC_SUCCESS); 7773 } 7774 7775 /*@C 7776 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7777 7778 Not collective 7779 7780 Input Parameters: 7781 + dm - The `DM` 7782 . section - The `PetscSection` describing the points (a local section) 7783 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7784 . point - The point defining the closure 7785 - useClPerm - Use the closure point permutation if available 7786 7787 Output Parameters: 7788 + numIndices - The number of dof indices in the closure of point with the input sections 7789 . indices - The dof indices 7790 . outOffsets - Array to write the field offsets into, or `NULL` 7791 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7792 7793 Level: advanced 7794 7795 Notes: 7796 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7797 7798 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7799 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7800 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7801 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7802 indices (with the above semantics) are implied. 7803 7804 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7805 `PetscSection`, `DMGetGlobalSection()` 7806 @*/ 7807 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7808 { 7809 /* Closure ordering */ 7810 PetscSection clSection; 7811 IS clPoints; 7812 const PetscInt *clp; 7813 PetscInt *points; 7814 const PetscInt *clperm = NULL; 7815 /* Dof permutation and sign flips */ 7816 const PetscInt **perms[32] = {NULL}; 7817 const PetscScalar **flips[32] = {NULL}; 7818 PetscScalar *valCopy = NULL; 7819 /* Hanging node constraints */ 7820 PetscInt *pointsC = NULL; 7821 PetscScalar *valuesC = NULL; 7822 PetscInt NclC, NiC; 7823 7824 PetscInt *idx; 7825 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7826 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7827 7828 PetscFunctionBeginHot; 7829 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7830 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7831 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7832 if (numIndices) PetscAssertPointer(numIndices, 6); 7833 if (indices) PetscAssertPointer(indices, 7); 7834 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7835 if (values) PetscAssertPointer(values, 9); 7836 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7837 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7838 PetscCall(PetscArrayzero(offsets, 32)); 7839 /* 1) Get points in closure */ 7840 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7841 if (useClPerm) { 7842 PetscInt depth, clsize; 7843 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7844 for (clsize = 0, p = 0; p < Ncl; p++) { 7845 PetscInt dof; 7846 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7847 clsize += dof; 7848 } 7849 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7850 } 7851 /* 2) Get number of indices on these points and field offsets from section */ 7852 for (p = 0; p < Ncl * 2; p += 2) { 7853 PetscInt dof, fdof; 7854 7855 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7856 for (f = 0; f < Nf; ++f) { 7857 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7858 offsets[f + 1] += fdof; 7859 } 7860 Ni += dof; 7861 } 7862 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7863 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7864 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7865 for (f = 0; f < PetscMax(1, Nf); ++f) { 7866 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7867 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7868 /* may need to apply sign changes to the element matrix */ 7869 if (values && flips[f]) { 7870 PetscInt foffset = offsets[f]; 7871 7872 for (p = 0; p < Ncl; ++p) { 7873 PetscInt pnt = points[2 * p], fdof; 7874 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7875 7876 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7877 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7878 if (flip) { 7879 PetscInt i, j, k; 7880 7881 if (!valCopy) { 7882 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7883 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7884 *values = valCopy; 7885 } 7886 for (i = 0; i < fdof; ++i) { 7887 PetscScalar fval = flip[i]; 7888 7889 for (k = 0; k < Ni; ++k) { 7890 valCopy[Ni * (foffset + i) + k] *= fval; 7891 valCopy[Ni * k + (foffset + i)] *= fval; 7892 } 7893 } 7894 } 7895 foffset += fdof; 7896 } 7897 } 7898 } 7899 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7900 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7901 if (NclC) { 7902 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7903 for (f = 0; f < PetscMax(1, Nf); ++f) { 7904 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7905 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7906 } 7907 for (f = 0; f < PetscMax(1, Nf); ++f) { 7908 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7909 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7910 } 7911 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7912 Ncl = NclC; 7913 Ni = NiC; 7914 points = pointsC; 7915 if (values) *values = valuesC; 7916 } 7917 /* 5) Calculate indices */ 7918 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7919 if (Nf) { 7920 PetscInt idxOff; 7921 PetscBool useFieldOffsets; 7922 7923 if (outOffsets) { 7924 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7925 } 7926 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7927 if (useFieldOffsets) { 7928 for (p = 0; p < Ncl; ++p) { 7929 const PetscInt pnt = points[p * 2]; 7930 7931 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7932 } 7933 } else { 7934 for (p = 0; p < Ncl; ++p) { 7935 const PetscInt pnt = points[p * 2]; 7936 7937 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7938 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7939 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7940 * global section. */ 7941 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7942 } 7943 } 7944 } else { 7945 PetscInt off = 0, idxOff; 7946 7947 for (p = 0; p < Ncl; ++p) { 7948 const PetscInt pnt = points[p * 2]; 7949 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7950 7951 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7952 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7953 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7954 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7955 } 7956 } 7957 /* 6) Cleanup */ 7958 for (f = 0; f < PetscMax(1, Nf); ++f) { 7959 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7960 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7961 } 7962 if (NclC) { 7963 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7964 } else { 7965 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7966 } 7967 7968 if (numIndices) *numIndices = Ni; 7969 if (indices) *indices = idx; 7970 PetscFunctionReturn(PETSC_SUCCESS); 7971 } 7972 7973 /*@C 7974 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7975 7976 Not collective 7977 7978 Input Parameters: 7979 + dm - The `DM` 7980 . section - The `PetscSection` describing the points (a local section) 7981 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7982 . point - The point defining the closure 7983 - useClPerm - Use the closure point permutation if available 7984 7985 Output Parameters: 7986 + numIndices - The number of dof indices in the closure of point with the input sections 7987 . indices - The dof indices 7988 . outOffsets - Array to write the field offsets into, or `NULL` 7989 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7990 7991 Level: advanced 7992 7993 Notes: 7994 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7995 7996 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7997 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7998 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7999 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8000 indices (with the above semantics) are implied. 8001 8002 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8003 @*/ 8004 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8005 { 8006 PetscFunctionBegin; 8007 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8008 PetscAssertPointer(indices, 7); 8009 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8010 PetscFunctionReturn(PETSC_SUCCESS); 8011 } 8012 8013 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8014 { 8015 DM_Plex *mesh = (DM_Plex *)dm->data; 8016 PetscInt *indices; 8017 PetscInt numIndices; 8018 const PetscScalar *valuesOrig = values; 8019 PetscErrorCode ierr; 8020 8021 PetscFunctionBegin; 8022 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8023 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8024 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8025 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8026 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8027 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8028 8029 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8030 8031 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8032 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8033 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8034 if (ierr) { 8035 PetscMPIInt rank; 8036 8037 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8038 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8039 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8040 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8041 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8042 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8043 } 8044 if (mesh->printFEM > 1) { 8045 PetscInt i; 8046 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8047 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8048 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8049 } 8050 8051 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8052 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8053 PetscFunctionReturn(PETSC_SUCCESS); 8054 } 8055 8056 /*@C 8057 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8058 8059 Not collective 8060 8061 Input Parameters: 8062 + dm - The `DM` 8063 . section - The section describing the layout in `v`, or `NULL` to use the default section 8064 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8065 . A - The matrix 8066 . point - The point in the `DM` 8067 . values - The array of values 8068 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8069 8070 Level: intermediate 8071 8072 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8073 @*/ 8074 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8075 { 8076 PetscFunctionBegin; 8077 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8078 PetscFunctionReturn(PETSC_SUCCESS); 8079 } 8080 8081 /*@C 8082 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8083 8084 Not collective 8085 8086 Input Parameters: 8087 + dmRow - The `DM` for the row fields 8088 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8089 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8090 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8091 . dmCol - The `DM` for the column fields 8092 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8093 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8094 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8095 . A - The matrix 8096 . point - The point in the `DM` 8097 . values - The array of values 8098 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8099 8100 Level: intermediate 8101 8102 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8103 @*/ 8104 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) 8105 { 8106 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8107 PetscInt *indicesRow, *indicesCol; 8108 PetscInt numIndicesRow, numIndicesCol; 8109 const PetscScalar *valuesOrig = values; 8110 PetscErrorCode ierr; 8111 8112 PetscFunctionBegin; 8113 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8114 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8115 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8116 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8117 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8118 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8119 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8120 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8121 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8122 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8123 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8124 8125 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8126 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8127 8128 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8129 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8130 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8131 if (ierr) { 8132 PetscMPIInt rank; 8133 8134 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8135 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8136 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8137 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8138 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8139 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8140 } 8141 8142 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8143 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8144 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8145 PetscFunctionReturn(PETSC_SUCCESS); 8146 } 8147 8148 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8149 { 8150 DM_Plex *mesh = (DM_Plex *)dmf->data; 8151 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8152 PetscInt *cpoints = NULL; 8153 PetscInt *findices, *cindices; 8154 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8155 PetscInt foffsets[32], coffsets[32]; 8156 DMPolytopeType ct; 8157 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8158 PetscErrorCode ierr; 8159 8160 PetscFunctionBegin; 8161 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8162 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8163 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8164 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8165 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8166 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8167 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8168 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8169 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8170 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8171 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8172 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8173 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8174 PetscCall(PetscArrayzero(foffsets, 32)); 8175 PetscCall(PetscArrayzero(coffsets, 32)); 8176 /* Column indices */ 8177 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8178 maxFPoints = numCPoints; 8179 /* Compress out points not in the section */ 8180 /* TODO: Squeeze out points with 0 dof as well */ 8181 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8182 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8183 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8184 cpoints[q * 2] = cpoints[p]; 8185 cpoints[q * 2 + 1] = cpoints[p + 1]; 8186 ++q; 8187 } 8188 } 8189 numCPoints = q; 8190 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8191 PetscInt fdof; 8192 8193 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8194 if (!dof) continue; 8195 for (f = 0; f < numFields; ++f) { 8196 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8197 coffsets[f + 1] += fdof; 8198 } 8199 numCIndices += dof; 8200 } 8201 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8202 /* Row indices */ 8203 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8204 { 8205 DMPlexTransform tr; 8206 DMPolytopeType *rct; 8207 PetscInt *rsize, *rcone, *rornt, Nt; 8208 8209 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8210 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8211 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8212 numSubcells = rsize[Nt - 1]; 8213 PetscCall(DMPlexTransformDestroy(&tr)); 8214 } 8215 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8216 for (r = 0, q = 0; r < numSubcells; ++r) { 8217 /* TODO Map from coarse to fine cells */ 8218 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8219 /* Compress out points not in the section */ 8220 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8221 for (p = 0; p < numFPoints * 2; p += 2) { 8222 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8223 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8224 if (!dof) continue; 8225 for (s = 0; s < q; ++s) 8226 if (fpoints[p] == ftotpoints[s * 2]) break; 8227 if (s < q) continue; 8228 ftotpoints[q * 2] = fpoints[p]; 8229 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8230 ++q; 8231 } 8232 } 8233 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8234 } 8235 numFPoints = q; 8236 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8237 PetscInt fdof; 8238 8239 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8240 if (!dof) continue; 8241 for (f = 0; f < numFields; ++f) { 8242 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8243 foffsets[f + 1] += fdof; 8244 } 8245 numFIndices += dof; 8246 } 8247 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8248 8249 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8250 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8251 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8252 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8253 if (numFields) { 8254 const PetscInt **permsF[32] = {NULL}; 8255 const PetscInt **permsC[32] = {NULL}; 8256 8257 for (f = 0; f < numFields; f++) { 8258 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8259 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8260 } 8261 for (p = 0; p < numFPoints; p++) { 8262 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8263 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8264 } 8265 for (p = 0; p < numCPoints; p++) { 8266 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8267 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8268 } 8269 for (f = 0; f < numFields; f++) { 8270 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8271 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8272 } 8273 } else { 8274 const PetscInt **permsF = NULL; 8275 const PetscInt **permsC = NULL; 8276 8277 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8278 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8279 for (p = 0, off = 0; p < numFPoints; p++) { 8280 const PetscInt *perm = permsF ? permsF[p] : NULL; 8281 8282 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8283 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8284 } 8285 for (p = 0, off = 0; p < numCPoints; p++) { 8286 const PetscInt *perm = permsC ? permsC[p] : NULL; 8287 8288 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8289 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8290 } 8291 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8292 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8293 } 8294 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8295 /* TODO: flips */ 8296 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8297 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8298 if (ierr) { 8299 PetscMPIInt rank; 8300 8301 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8302 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8303 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8304 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8305 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8306 } 8307 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8308 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8309 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8310 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8311 PetscFunctionReturn(PETSC_SUCCESS); 8312 } 8313 8314 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8315 { 8316 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8317 PetscInt *cpoints = NULL; 8318 PetscInt foffsets[32], coffsets[32]; 8319 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8320 DMPolytopeType ct; 8321 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8322 8323 PetscFunctionBegin; 8324 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8325 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8326 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8327 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8328 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8329 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8330 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8331 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8332 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8333 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8334 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8335 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8336 PetscCall(PetscArrayzero(foffsets, 32)); 8337 PetscCall(PetscArrayzero(coffsets, 32)); 8338 /* Column indices */ 8339 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8340 maxFPoints = numCPoints; 8341 /* Compress out points not in the section */ 8342 /* TODO: Squeeze out points with 0 dof as well */ 8343 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8344 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8345 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8346 cpoints[q * 2] = cpoints[p]; 8347 cpoints[q * 2 + 1] = cpoints[p + 1]; 8348 ++q; 8349 } 8350 } 8351 numCPoints = q; 8352 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8353 PetscInt fdof; 8354 8355 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8356 if (!dof) continue; 8357 for (f = 0; f < numFields; ++f) { 8358 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8359 coffsets[f + 1] += fdof; 8360 } 8361 numCIndices += dof; 8362 } 8363 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8364 /* Row indices */ 8365 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8366 { 8367 DMPlexTransform tr; 8368 DMPolytopeType *rct; 8369 PetscInt *rsize, *rcone, *rornt, Nt; 8370 8371 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8372 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8373 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8374 numSubcells = rsize[Nt - 1]; 8375 PetscCall(DMPlexTransformDestroy(&tr)); 8376 } 8377 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8378 for (r = 0, q = 0; r < numSubcells; ++r) { 8379 /* TODO Map from coarse to fine cells */ 8380 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8381 /* Compress out points not in the section */ 8382 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8383 for (p = 0; p < numFPoints * 2; p += 2) { 8384 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8385 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8386 if (!dof) continue; 8387 for (s = 0; s < q; ++s) 8388 if (fpoints[p] == ftotpoints[s * 2]) break; 8389 if (s < q) continue; 8390 ftotpoints[q * 2] = fpoints[p]; 8391 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8392 ++q; 8393 } 8394 } 8395 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8396 } 8397 numFPoints = q; 8398 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8399 PetscInt fdof; 8400 8401 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8402 if (!dof) continue; 8403 for (f = 0; f < numFields; ++f) { 8404 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8405 foffsets[f + 1] += fdof; 8406 } 8407 numFIndices += dof; 8408 } 8409 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8410 8411 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8412 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8413 if (numFields) { 8414 const PetscInt **permsF[32] = {NULL}; 8415 const PetscInt **permsC[32] = {NULL}; 8416 8417 for (f = 0; f < numFields; f++) { 8418 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8419 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8420 } 8421 for (p = 0; p < numFPoints; p++) { 8422 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8423 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8424 } 8425 for (p = 0; p < numCPoints; p++) { 8426 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8427 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8428 } 8429 for (f = 0; f < numFields; f++) { 8430 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8431 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8432 } 8433 } else { 8434 const PetscInt **permsF = NULL; 8435 const PetscInt **permsC = NULL; 8436 8437 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8438 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8439 for (p = 0, off = 0; p < numFPoints; p++) { 8440 const PetscInt *perm = permsF ? permsF[p] : NULL; 8441 8442 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8443 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8444 } 8445 for (p = 0, off = 0; p < numCPoints; p++) { 8446 const PetscInt *perm = permsC ? permsC[p] : NULL; 8447 8448 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8449 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8450 } 8451 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8452 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8453 } 8454 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8455 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8456 PetscFunctionReturn(PETSC_SUCCESS); 8457 } 8458 8459 /*@C 8460 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8461 8462 Input Parameter: 8463 . dm - The `DMPLEX` object 8464 8465 Output Parameter: 8466 . cellHeight - The height of a cell 8467 8468 Level: developer 8469 8470 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8471 @*/ 8472 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8473 { 8474 DM_Plex *mesh = (DM_Plex *)dm->data; 8475 8476 PetscFunctionBegin; 8477 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8478 PetscAssertPointer(cellHeight, 2); 8479 *cellHeight = mesh->vtkCellHeight; 8480 PetscFunctionReturn(PETSC_SUCCESS); 8481 } 8482 8483 /*@C 8484 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8485 8486 Input Parameters: 8487 + dm - The `DMPLEX` object 8488 - cellHeight - The height of a cell 8489 8490 Level: developer 8491 8492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8493 @*/ 8494 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8495 { 8496 DM_Plex *mesh = (DM_Plex *)dm->data; 8497 8498 PetscFunctionBegin; 8499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8500 mesh->vtkCellHeight = cellHeight; 8501 PetscFunctionReturn(PETSC_SUCCESS); 8502 } 8503 8504 /*@ 8505 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8506 8507 Input Parameters: 8508 + dm - The `DMPLEX` object 8509 - ct - The `DMPolytopeType` of the cell 8510 8511 Output Parameters: 8512 + start - The first cell of this type, or `NULL` 8513 - end - The upper bound on this celltype, or `NULL` 8514 8515 Level: advanced 8516 8517 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8518 @*/ 8519 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8520 { 8521 DM_Plex *mesh = (DM_Plex *)dm->data; 8522 DMLabel label; 8523 PetscInt pStart, pEnd; 8524 8525 PetscFunctionBegin; 8526 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8527 if (start) { 8528 PetscAssertPointer(start, 3); 8529 *start = 0; 8530 } 8531 if (end) { 8532 PetscAssertPointer(end, 4); 8533 *end = 0; 8534 } 8535 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8536 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8537 if (mesh->tr) { 8538 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8539 } else { 8540 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8541 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8542 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8543 } 8544 PetscFunctionReturn(PETSC_SUCCESS); 8545 } 8546 8547 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8548 { 8549 PetscSection section, globalSection; 8550 PetscInt *numbers, p; 8551 8552 PetscFunctionBegin; 8553 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8554 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8555 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8556 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8557 PetscCall(PetscSectionSetUp(section)); 8558 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8559 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8560 for (p = pStart; p < pEnd; ++p) { 8561 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8562 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8563 else numbers[p - pStart] += shift; 8564 } 8565 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8566 if (globalSize) { 8567 PetscLayout layout; 8568 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8569 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8570 PetscCall(PetscLayoutDestroy(&layout)); 8571 } 8572 PetscCall(PetscSectionDestroy(§ion)); 8573 PetscCall(PetscSectionDestroy(&globalSection)); 8574 PetscFunctionReturn(PETSC_SUCCESS); 8575 } 8576 8577 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8578 { 8579 PetscInt cellHeight, cStart, cEnd; 8580 8581 PetscFunctionBegin; 8582 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8583 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8584 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8585 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8586 PetscFunctionReturn(PETSC_SUCCESS); 8587 } 8588 8589 /*@ 8590 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8591 8592 Input Parameter: 8593 . dm - The `DMPLEX` object 8594 8595 Output Parameter: 8596 . globalCellNumbers - Global cell numbers for all cells on this process 8597 8598 Level: developer 8599 8600 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8601 @*/ 8602 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8603 { 8604 DM_Plex *mesh = (DM_Plex *)dm->data; 8605 8606 PetscFunctionBegin; 8607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8608 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8609 *globalCellNumbers = mesh->globalCellNumbers; 8610 PetscFunctionReturn(PETSC_SUCCESS); 8611 } 8612 8613 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8614 { 8615 PetscInt vStart, vEnd; 8616 8617 PetscFunctionBegin; 8618 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8619 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8620 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8621 PetscFunctionReturn(PETSC_SUCCESS); 8622 } 8623 8624 /*@ 8625 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8626 8627 Input Parameter: 8628 . dm - The `DMPLEX` object 8629 8630 Output Parameter: 8631 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8632 8633 Level: developer 8634 8635 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8636 @*/ 8637 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8638 { 8639 DM_Plex *mesh = (DM_Plex *)dm->data; 8640 8641 PetscFunctionBegin; 8642 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8643 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8644 *globalVertexNumbers = mesh->globalVertexNumbers; 8645 PetscFunctionReturn(PETSC_SUCCESS); 8646 } 8647 8648 /*@ 8649 DMPlexCreatePointNumbering - Create a global numbering for all points. 8650 8651 Collective 8652 8653 Input Parameter: 8654 . dm - The `DMPLEX` object 8655 8656 Output Parameter: 8657 . globalPointNumbers - Global numbers for all points on this process 8658 8659 Level: developer 8660 8661 Notes: 8662 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8663 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8664 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8665 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8666 8667 The partitioned mesh is 8668 ``` 8669 (2)--0--(3)--1--(4) (1)--0--(2) 8670 ``` 8671 and its global numbering is 8672 ``` 8673 (3)--0--(4)--1--(5)--2--(6) 8674 ``` 8675 Then the global numbering is provided as 8676 ``` 8677 [0] Number of indices in set 5 8678 [0] 0 0 8679 [0] 1 1 8680 [0] 2 3 8681 [0] 3 4 8682 [0] 4 -6 8683 [1] Number of indices in set 3 8684 [1] 0 2 8685 [1] 1 5 8686 [1] 2 6 8687 ``` 8688 8689 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8690 @*/ 8691 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8692 { 8693 IS nums[4]; 8694 PetscInt depths[4], gdepths[4], starts[4]; 8695 PetscInt depth, d, shift = 0; 8696 PetscBool empty = PETSC_FALSE; 8697 8698 PetscFunctionBegin; 8699 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8700 PetscCall(DMPlexGetDepth(dm, &depth)); 8701 // For unstratified meshes use dim instead of depth 8702 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8703 // If any stratum is empty, we must mark all empty 8704 for (d = 0; d <= depth; ++d) { 8705 PetscInt end; 8706 8707 depths[d] = depth - d; 8708 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8709 if (!(starts[d] - end)) empty = PETSC_TRUE; 8710 } 8711 if (empty) 8712 for (d = 0; d <= depth; ++d) { 8713 depths[d] = -1; 8714 starts[d] = -1; 8715 } 8716 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8717 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8718 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]); 8719 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8720 for (d = 0; d <= depth; ++d) { 8721 PetscInt pStart, pEnd, gsize; 8722 8723 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8724 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8725 shift += gsize; 8726 } 8727 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8728 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8729 PetscFunctionReturn(PETSC_SUCCESS); 8730 } 8731 8732 /*@ 8733 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8734 8735 Input Parameter: 8736 . dm - The `DMPLEX` object 8737 8738 Output Parameter: 8739 . ranks - The rank field 8740 8741 Options Database Key: 8742 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8743 8744 Level: intermediate 8745 8746 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8747 @*/ 8748 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8749 { 8750 DM rdm; 8751 PetscFE fe; 8752 PetscScalar *r; 8753 PetscMPIInt rank; 8754 DMPolytopeType ct; 8755 PetscInt dim, cStart, cEnd, c; 8756 PetscBool simplex; 8757 8758 PetscFunctionBeginUser; 8759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8760 PetscAssertPointer(ranks, 2); 8761 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8762 PetscCall(DMClone(dm, &rdm)); 8763 PetscCall(DMGetDimension(rdm, &dim)); 8764 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8765 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8766 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8767 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8768 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8769 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8770 PetscCall(PetscFEDestroy(&fe)); 8771 PetscCall(DMCreateDS(rdm)); 8772 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8773 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8774 PetscCall(VecGetArray(*ranks, &r)); 8775 for (c = cStart; c < cEnd; ++c) { 8776 PetscScalar *lr; 8777 8778 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8779 if (lr) *lr = rank; 8780 } 8781 PetscCall(VecRestoreArray(*ranks, &r)); 8782 PetscCall(DMDestroy(&rdm)); 8783 PetscFunctionReturn(PETSC_SUCCESS); 8784 } 8785 8786 /*@ 8787 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8788 8789 Input Parameters: 8790 + dm - The `DMPLEX` 8791 - label - The `DMLabel` 8792 8793 Output Parameter: 8794 . val - The label value field 8795 8796 Options Database Key: 8797 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8798 8799 Level: intermediate 8800 8801 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8802 @*/ 8803 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8804 { 8805 DM rdm; 8806 PetscFE fe; 8807 PetscScalar *v; 8808 PetscInt dim, cStart, cEnd, c; 8809 8810 PetscFunctionBeginUser; 8811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8812 PetscAssertPointer(label, 2); 8813 PetscAssertPointer(val, 3); 8814 PetscCall(DMClone(dm, &rdm)); 8815 PetscCall(DMGetDimension(rdm, &dim)); 8816 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8817 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8818 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8819 PetscCall(PetscFEDestroy(&fe)); 8820 PetscCall(DMCreateDS(rdm)); 8821 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8822 PetscCall(DMCreateGlobalVector(rdm, val)); 8823 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8824 PetscCall(VecGetArray(*val, &v)); 8825 for (c = cStart; c < cEnd; ++c) { 8826 PetscScalar *lv; 8827 PetscInt cval; 8828 8829 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8830 PetscCall(DMLabelGetValue(label, c, &cval)); 8831 *lv = cval; 8832 } 8833 PetscCall(VecRestoreArray(*val, &v)); 8834 PetscCall(DMDestroy(&rdm)); 8835 PetscFunctionReturn(PETSC_SUCCESS); 8836 } 8837 8838 /*@ 8839 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8840 8841 Input Parameter: 8842 . dm - The `DMPLEX` object 8843 8844 Level: developer 8845 8846 Notes: 8847 This is a useful diagnostic when creating meshes programmatically. 8848 8849 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8850 8851 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8852 @*/ 8853 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8854 { 8855 PetscSection coneSection, supportSection; 8856 const PetscInt *cone, *support; 8857 PetscInt coneSize, c, supportSize, s; 8858 PetscInt pStart, pEnd, p, pp, csize, ssize; 8859 PetscBool storagecheck = PETSC_TRUE; 8860 8861 PetscFunctionBegin; 8862 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8863 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8864 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8865 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8866 /* Check that point p is found in the support of its cone points, and vice versa */ 8867 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8868 for (p = pStart; p < pEnd; ++p) { 8869 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8870 PetscCall(DMPlexGetCone(dm, p, &cone)); 8871 for (c = 0; c < coneSize; ++c) { 8872 PetscBool dup = PETSC_FALSE; 8873 PetscInt d; 8874 for (d = c - 1; d >= 0; --d) { 8875 if (cone[c] == cone[d]) { 8876 dup = PETSC_TRUE; 8877 break; 8878 } 8879 } 8880 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8881 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8882 for (s = 0; s < supportSize; ++s) { 8883 if (support[s] == p) break; 8884 } 8885 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8886 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8887 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8888 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8889 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8890 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8891 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8892 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]); 8893 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8894 } 8895 } 8896 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8897 if (p != pp) { 8898 storagecheck = PETSC_FALSE; 8899 continue; 8900 } 8901 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8902 PetscCall(DMPlexGetSupport(dm, p, &support)); 8903 for (s = 0; s < supportSize; ++s) { 8904 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8905 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8906 for (c = 0; c < coneSize; ++c) { 8907 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8908 if (cone[c] != pp) { 8909 c = 0; 8910 break; 8911 } 8912 if (cone[c] == p) break; 8913 } 8914 if (c >= coneSize) { 8915 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8916 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8917 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8918 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8919 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8920 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8921 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8922 } 8923 } 8924 } 8925 if (storagecheck) { 8926 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8927 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8928 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8929 } 8930 PetscFunctionReturn(PETSC_SUCCESS); 8931 } 8932 8933 /* 8934 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. 8935 */ 8936 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8937 { 8938 DMPolytopeType cct; 8939 PetscInt ptpoints[4]; 8940 const PetscInt *cone, *ccone, *ptcone; 8941 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8942 8943 PetscFunctionBegin; 8944 *unsplit = 0; 8945 switch (ct) { 8946 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8947 ptpoints[npt++] = c; 8948 break; 8949 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8950 PetscCall(DMPlexGetCone(dm, c, &cone)); 8951 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8952 for (cp = 0; cp < coneSize; ++cp) { 8953 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8954 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8955 } 8956 break; 8957 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8958 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8959 PetscCall(DMPlexGetCone(dm, c, &cone)); 8960 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8961 for (cp = 0; cp < coneSize; ++cp) { 8962 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8963 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8964 for (ccp = 0; ccp < cconeSize; ++ccp) { 8965 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8966 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8967 PetscInt p; 8968 for (p = 0; p < npt; ++p) 8969 if (ptpoints[p] == ccone[ccp]) break; 8970 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8971 } 8972 } 8973 } 8974 break; 8975 default: 8976 break; 8977 } 8978 for (pt = 0; pt < npt; ++pt) { 8979 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8980 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8981 } 8982 PetscFunctionReturn(PETSC_SUCCESS); 8983 } 8984 8985 /*@ 8986 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8987 8988 Input Parameters: 8989 + dm - The `DMPLEX` object 8990 - cellHeight - Normally 0 8991 8992 Level: developer 8993 8994 Notes: 8995 This is a useful diagnostic when creating meshes programmatically. 8996 Currently applicable only to homogeneous simplex or tensor meshes. 8997 8998 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8999 9000 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9001 @*/ 9002 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9003 { 9004 DMPlexInterpolatedFlag interp; 9005 DMPolytopeType ct; 9006 PetscInt vStart, vEnd, cStart, cEnd, c; 9007 9008 PetscFunctionBegin; 9009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9010 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9011 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9012 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9013 for (c = cStart; c < cEnd; ++c) { 9014 PetscInt *closure = NULL; 9015 PetscInt coneSize, closureSize, cl, Nv = 0; 9016 9017 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9018 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9019 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9020 if (interp == DMPLEX_INTERPOLATED_FULL) { 9021 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9022 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)); 9023 } 9024 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9025 for (cl = 0; cl < closureSize * 2; cl += 2) { 9026 const PetscInt p = closure[cl]; 9027 if ((p >= vStart) && (p < vEnd)) ++Nv; 9028 } 9029 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9030 /* Special Case: Tensor faces with identified vertices */ 9031 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9032 PetscInt unsplit; 9033 9034 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9035 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9036 } 9037 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)); 9038 } 9039 PetscFunctionReturn(PETSC_SUCCESS); 9040 } 9041 9042 /*@ 9043 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9044 9045 Collective 9046 9047 Input Parameters: 9048 + dm - The `DMPLEX` object 9049 - cellHeight - Normally 0 9050 9051 Level: developer 9052 9053 Notes: 9054 This is a useful diagnostic when creating meshes programmatically. 9055 This routine is only relevant for meshes that are fully interpolated across all ranks. 9056 It will error out if a partially interpolated mesh is given on some rank. 9057 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9058 9059 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9060 9061 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9062 @*/ 9063 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9064 { 9065 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9066 DMPlexInterpolatedFlag interpEnum; 9067 9068 PetscFunctionBegin; 9069 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9070 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9071 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9072 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9073 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9074 PetscFunctionReturn(PETSC_SUCCESS); 9075 } 9076 9077 PetscCall(DMGetDimension(dm, &dim)); 9078 PetscCall(DMPlexGetDepth(dm, &depth)); 9079 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9080 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9081 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9082 for (c = cStart; c < cEnd; ++c) { 9083 const PetscInt *cone, *ornt, *faceSizes, *faces; 9084 const DMPolytopeType *faceTypes; 9085 DMPolytopeType ct; 9086 PetscInt numFaces, coneSize, f; 9087 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9088 9089 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9090 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9091 if (unsplit) continue; 9092 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9093 PetscCall(DMPlexGetCone(dm, c, &cone)); 9094 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9095 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9096 for (cl = 0; cl < closureSize * 2; cl += 2) { 9097 const PetscInt p = closure[cl]; 9098 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9099 } 9100 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9101 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); 9102 for (f = 0; f < numFaces; ++f) { 9103 DMPolytopeType fct; 9104 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9105 9106 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9107 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9108 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9109 const PetscInt p = fclosure[cl]; 9110 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9111 } 9112 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]); 9113 for (v = 0; v < fnumCorners; ++v) { 9114 if (fclosure[v] != faces[fOff + v]) { 9115 PetscInt v1; 9116 9117 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9118 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9119 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9120 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9121 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9122 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]); 9123 } 9124 } 9125 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9126 fOff += faceSizes[f]; 9127 } 9128 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9129 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9130 } 9131 } 9132 PetscFunctionReturn(PETSC_SUCCESS); 9133 } 9134 9135 /*@ 9136 DMPlexCheckGeometry - Check the geometry of mesh cells 9137 9138 Input Parameter: 9139 . dm - The `DMPLEX` object 9140 9141 Level: developer 9142 9143 Notes: 9144 This is a useful diagnostic when creating meshes programmatically. 9145 9146 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9147 9148 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9149 @*/ 9150 PetscErrorCode DMPlexCheckGeometry(DM dm) 9151 { 9152 Vec coordinates; 9153 PetscReal detJ, J[9], refVol = 1.0; 9154 PetscReal vol; 9155 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9156 9157 PetscFunctionBegin; 9158 PetscCall(DMGetDimension(dm, &dim)); 9159 PetscCall(DMGetCoordinateDim(dm, &dE)); 9160 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9161 PetscCall(DMPlexGetDepth(dm, &depth)); 9162 for (d = 0; d < dim; ++d) refVol *= 2.0; 9163 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9164 /* Make sure local coordinates are created, because that step is collective */ 9165 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9166 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9167 for (c = cStart; c < cEnd; ++c) { 9168 DMPolytopeType ct; 9169 PetscInt unsplit; 9170 PetscBool ignoreZeroVol = PETSC_FALSE; 9171 9172 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9173 switch (ct) { 9174 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9175 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9176 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9177 ignoreZeroVol = PETSC_TRUE; 9178 break; 9179 default: 9180 break; 9181 } 9182 switch (ct) { 9183 case DM_POLYTOPE_TRI_PRISM: 9184 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9185 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9186 case DM_POLYTOPE_PYRAMID: 9187 continue; 9188 default: 9189 break; 9190 } 9191 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9192 if (unsplit) continue; 9193 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9194 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); 9195 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9196 /* This should work with periodicity since DG coordinates should be used */ 9197 if (depth > 1) { 9198 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9199 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); 9200 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9201 } 9202 } 9203 PetscFunctionReturn(PETSC_SUCCESS); 9204 } 9205 9206 /*@ 9207 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9208 9209 Collective 9210 9211 Input Parameters: 9212 + dm - The `DMPLEX` object 9213 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9214 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9215 9216 Level: developer 9217 9218 Notes: 9219 This is mainly intended for debugging/testing purposes. 9220 9221 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9222 9223 Extra roots can come from periodic cuts, where additional points appear on the boundary 9224 9225 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9226 @*/ 9227 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9228 { 9229 PetscInt l, nleaves, nroots, overlap; 9230 const PetscInt *locals; 9231 const PetscSFNode *remotes; 9232 PetscBool distributed; 9233 MPI_Comm comm; 9234 PetscMPIInt rank; 9235 9236 PetscFunctionBegin; 9237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9238 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9239 else pointSF = dm->sf; 9240 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9241 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9242 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9243 { 9244 PetscMPIInt mpiFlag; 9245 9246 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9247 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9248 } 9249 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9250 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9251 if (!distributed) { 9252 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); 9253 PetscFunctionReturn(PETSC_SUCCESS); 9254 } 9255 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); 9256 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9257 9258 /* Check SF graph is compatible with DMPlex chart */ 9259 { 9260 PetscInt pStart, pEnd, maxLeaf; 9261 9262 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9263 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9264 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9265 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9266 } 9267 9268 /* Check Point SF has no local points referenced */ 9269 for (l = 0; l < nleaves; l++) { 9270 PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index); 9271 } 9272 9273 /* Check there are no cells in interface */ 9274 if (!overlap) { 9275 PetscInt cellHeight, cStart, cEnd; 9276 9277 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9278 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9279 for (l = 0; l < nleaves; ++l) { 9280 const PetscInt point = locals ? locals[l] : l; 9281 9282 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9283 } 9284 } 9285 9286 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9287 { 9288 const PetscInt *rootdegree; 9289 9290 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9291 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9292 for (l = 0; l < nleaves; ++l) { 9293 const PetscInt point = locals ? locals[l] : l; 9294 const PetscInt *cone; 9295 PetscInt coneSize, c, idx; 9296 9297 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9298 PetscCall(DMPlexGetCone(dm, point, &cone)); 9299 for (c = 0; c < coneSize; ++c) { 9300 if (!rootdegree[cone[c]]) { 9301 if (locals) { 9302 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9303 } else { 9304 idx = (cone[c] < nleaves) ? cone[c] : -1; 9305 } 9306 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9307 } 9308 } 9309 } 9310 } 9311 PetscFunctionReturn(PETSC_SUCCESS); 9312 } 9313 9314 /*@ 9315 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9316 9317 Input Parameter: 9318 . dm - The `DMPLEX` object 9319 9320 Level: developer 9321 9322 Notes: 9323 This is a useful diagnostic when creating meshes programmatically. 9324 9325 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9326 9327 Currently does not include `DMPlexCheckCellShape()`. 9328 9329 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9330 @*/ 9331 PetscErrorCode DMPlexCheck(DM dm) 9332 { 9333 PetscInt cellHeight; 9334 9335 PetscFunctionBegin; 9336 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9337 PetscCall(DMPlexCheckSymmetry(dm)); 9338 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9339 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9340 PetscCall(DMPlexCheckGeometry(dm)); 9341 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9342 PetscCall(DMPlexCheckInterfaceCones(dm)); 9343 PetscFunctionReturn(PETSC_SUCCESS); 9344 } 9345 9346 typedef struct cell_stats { 9347 PetscReal min, max, sum, squaresum; 9348 PetscInt count; 9349 } cell_stats_t; 9350 9351 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9352 { 9353 PetscInt i, N = *len; 9354 9355 for (i = 0; i < N; i++) { 9356 cell_stats_t *A = (cell_stats_t *)a; 9357 cell_stats_t *B = (cell_stats_t *)b; 9358 9359 B->min = PetscMin(A->min, B->min); 9360 B->max = PetscMax(A->max, B->max); 9361 B->sum += A->sum; 9362 B->squaresum += A->squaresum; 9363 B->count += A->count; 9364 } 9365 } 9366 9367 /*@ 9368 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9369 9370 Collective 9371 9372 Input Parameters: 9373 + dm - The `DMPLEX` object 9374 . output - If true, statistics will be displayed on `stdout` 9375 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9376 9377 Level: developer 9378 9379 Notes: 9380 This is mainly intended for debugging/testing purposes. 9381 9382 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9383 9384 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9385 @*/ 9386 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9387 { 9388 DM dmCoarse; 9389 cell_stats_t stats, globalStats; 9390 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9391 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9392 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9393 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9394 PetscMPIInt rank, size; 9395 9396 PetscFunctionBegin; 9397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9398 stats.min = PETSC_MAX_REAL; 9399 stats.max = PETSC_MIN_REAL; 9400 stats.sum = stats.squaresum = 0.; 9401 stats.count = 0; 9402 9403 PetscCallMPI(MPI_Comm_size(comm, &size)); 9404 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9405 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9406 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9407 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9408 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9409 for (c = cStart; c < cEnd; c++) { 9410 PetscInt i; 9411 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9412 9413 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9414 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9415 for (i = 0; i < PetscSqr(cdim); ++i) { 9416 frobJ += J[i] * J[i]; 9417 frobInvJ += invJ[i] * invJ[i]; 9418 } 9419 cond2 = frobJ * frobInvJ; 9420 cond = PetscSqrtReal(cond2); 9421 9422 stats.min = PetscMin(stats.min, cond); 9423 stats.max = PetscMax(stats.max, cond); 9424 stats.sum += cond; 9425 stats.squaresum += cond2; 9426 stats.count++; 9427 if (output && cond > limit) { 9428 PetscSection coordSection; 9429 Vec coordsLocal; 9430 PetscScalar *coords = NULL; 9431 PetscInt Nv, d, clSize, cl, *closure = NULL; 9432 9433 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9434 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9435 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9436 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9437 for (i = 0; i < Nv / cdim; ++i) { 9438 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9439 for (d = 0; d < cdim; ++d) { 9440 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9441 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9442 } 9443 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9444 } 9445 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9446 for (cl = 0; cl < clSize * 2; cl += 2) { 9447 const PetscInt edge = closure[cl]; 9448 9449 if ((edge >= eStart) && (edge < eEnd)) { 9450 PetscReal len; 9451 9452 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9453 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9454 } 9455 } 9456 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9457 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9458 } 9459 } 9460 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9461 9462 if (size > 1) { 9463 PetscMPIInt blockLengths[2] = {4, 1}; 9464 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9465 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9466 MPI_Op statReduce; 9467 9468 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9469 PetscCallMPI(MPI_Type_commit(&statType)); 9470 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9471 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9472 PetscCallMPI(MPI_Op_free(&statReduce)); 9473 PetscCallMPI(MPI_Type_free(&statType)); 9474 } else { 9475 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9476 } 9477 if (rank == 0) { 9478 count = globalStats.count; 9479 min = globalStats.min; 9480 max = globalStats.max; 9481 mean = globalStats.sum / globalStats.count; 9482 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9483 } 9484 9485 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)); 9486 PetscCall(PetscFree2(J, invJ)); 9487 9488 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9489 if (dmCoarse) { 9490 PetscBool isplex; 9491 9492 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9493 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9494 } 9495 PetscFunctionReturn(PETSC_SUCCESS); 9496 } 9497 9498 /*@ 9499 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9500 orthogonal quality below given tolerance. 9501 9502 Collective 9503 9504 Input Parameters: 9505 + dm - The `DMPLEX` object 9506 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9507 - atol - [0, 1] Absolute tolerance for tagging cells. 9508 9509 Output Parameters: 9510 + OrthQual - `Vec` containing orthogonal quality per cell 9511 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9512 9513 Options Database Keys: 9514 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9515 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9516 9517 Level: intermediate 9518 9519 Notes: 9520 Orthogonal quality is given by the following formula\: 9521 9522 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9523 9524 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 9525 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9526 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9527 calculating the cosine of the angle between these vectors. 9528 9529 Orthogonal quality ranges from 1 (best) to 0 (worst). 9530 9531 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9532 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9533 9534 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9535 9536 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9537 @*/ 9538 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9539 { 9540 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9541 PetscInt *idx; 9542 PetscScalar *oqVals; 9543 const PetscScalar *cellGeomArr, *faceGeomArr; 9544 PetscReal *ci, *fi, *Ai; 9545 MPI_Comm comm; 9546 Vec cellgeom, facegeom; 9547 DM dmFace, dmCell; 9548 IS glob; 9549 ISLocalToGlobalMapping ltog; 9550 PetscViewer vwr; 9551 9552 PetscFunctionBegin; 9553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9554 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9555 PetscAssertPointer(OrthQual, 4); 9556 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9557 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9558 PetscCall(DMGetDimension(dm, &nc)); 9559 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9560 { 9561 DMPlexInterpolatedFlag interpFlag; 9562 9563 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9564 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9565 PetscMPIInt rank; 9566 9567 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9568 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9569 } 9570 } 9571 if (OrthQualLabel) { 9572 PetscAssertPointer(OrthQualLabel, 5); 9573 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9574 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9575 } else { 9576 *OrthQualLabel = NULL; 9577 } 9578 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9579 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9580 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9581 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9582 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9583 PetscCall(VecCreate(comm, OrthQual)); 9584 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9585 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9586 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9587 PetscCall(VecSetUp(*OrthQual)); 9588 PetscCall(ISDestroy(&glob)); 9589 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9590 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9591 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9592 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9593 PetscCall(VecGetDM(cellgeom, &dmCell)); 9594 PetscCall(VecGetDM(facegeom, &dmFace)); 9595 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9596 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9597 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9598 PetscInt cellarr[2], *adj = NULL; 9599 PetscScalar *cArr, *fArr; 9600 PetscReal minvalc = 1.0, minvalf = 1.0; 9601 PetscFVCellGeom *cg; 9602 9603 idx[cellIter] = cell - cStart; 9604 cellarr[0] = cell; 9605 /* Make indexing into cellGeom easier */ 9606 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9607 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9608 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9609 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9610 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9611 PetscInt i; 9612 const PetscInt neigh = adj[cellneigh]; 9613 PetscReal normci = 0, normfi = 0, normai = 0; 9614 PetscFVCellGeom *cgneigh; 9615 PetscFVFaceGeom *fg; 9616 9617 /* Don't count ourselves in the neighbor list */ 9618 if (neigh == cell) continue; 9619 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9620 cellarr[1] = neigh; 9621 { 9622 PetscInt numcovpts; 9623 const PetscInt *covpts; 9624 9625 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9626 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9627 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9628 } 9629 9630 /* Compute c_i, f_i and their norms */ 9631 for (i = 0; i < nc; i++) { 9632 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9633 fi[i] = fg->centroid[i] - cg->centroid[i]; 9634 Ai[i] = fg->normal[i]; 9635 normci += PetscPowReal(ci[i], 2); 9636 normfi += PetscPowReal(fi[i], 2); 9637 normai += PetscPowReal(Ai[i], 2); 9638 } 9639 normci = PetscSqrtReal(normci); 9640 normfi = PetscSqrtReal(normfi); 9641 normai = PetscSqrtReal(normai); 9642 9643 /* Normalize and compute for each face-cell-normal pair */ 9644 for (i = 0; i < nc; i++) { 9645 ci[i] = ci[i] / normci; 9646 fi[i] = fi[i] / normfi; 9647 Ai[i] = Ai[i] / normai; 9648 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9649 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9650 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9651 } 9652 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9653 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9654 } 9655 PetscCall(PetscFree(adj)); 9656 PetscCall(PetscFree2(cArr, fArr)); 9657 /* Defer to cell if they're equal */ 9658 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9659 if (OrthQualLabel) { 9660 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9661 } 9662 } 9663 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9664 PetscCall(VecAssemblyBegin(*OrthQual)); 9665 PetscCall(VecAssemblyEnd(*OrthQual)); 9666 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9667 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9668 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9669 if (OrthQualLabel) { 9670 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9671 } 9672 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9673 PetscCall(PetscViewerDestroy(&vwr)); 9674 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9675 PetscFunctionReturn(PETSC_SUCCESS); 9676 } 9677 9678 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9679 * interpolator construction */ 9680 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9681 { 9682 PetscSection section, newSection, gsection; 9683 PetscSF sf; 9684 PetscBool hasConstraints, ghasConstraints; 9685 9686 PetscFunctionBegin; 9687 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9688 PetscAssertPointer(odm, 2); 9689 PetscCall(DMGetLocalSection(dm, §ion)); 9690 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9691 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9692 if (!ghasConstraints) { 9693 PetscCall(PetscObjectReference((PetscObject)dm)); 9694 *odm = dm; 9695 PetscFunctionReturn(PETSC_SUCCESS); 9696 } 9697 PetscCall(DMClone(dm, odm)); 9698 PetscCall(DMCopyFields(dm, *odm)); 9699 PetscCall(DMGetLocalSection(*odm, &newSection)); 9700 PetscCall(DMGetPointSF(*odm, &sf)); 9701 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9702 PetscCall(DMSetGlobalSection(*odm, gsection)); 9703 PetscCall(PetscSectionDestroy(&gsection)); 9704 PetscFunctionReturn(PETSC_SUCCESS); 9705 } 9706 9707 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9708 { 9709 DM dmco, dmfo; 9710 Mat interpo; 9711 Vec rscale; 9712 Vec cglobalo, clocal; 9713 Vec fglobal, fglobalo, flocal; 9714 PetscBool regular; 9715 9716 PetscFunctionBegin; 9717 PetscCall(DMGetFullDM(dmc, &dmco)); 9718 PetscCall(DMGetFullDM(dmf, &dmfo)); 9719 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9720 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9721 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9722 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9723 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9724 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9725 PetscCall(VecSet(cglobalo, 0.)); 9726 PetscCall(VecSet(clocal, 0.)); 9727 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9728 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9729 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9730 PetscCall(VecSet(fglobal, 0.)); 9731 PetscCall(VecSet(fglobalo, 0.)); 9732 PetscCall(VecSet(flocal, 0.)); 9733 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9734 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9735 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9736 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9737 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9738 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9739 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9740 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9741 *shift = fglobal; 9742 PetscCall(VecDestroy(&flocal)); 9743 PetscCall(VecDestroy(&fglobalo)); 9744 PetscCall(VecDestroy(&clocal)); 9745 PetscCall(VecDestroy(&cglobalo)); 9746 PetscCall(VecDestroy(&rscale)); 9747 PetscCall(MatDestroy(&interpo)); 9748 PetscCall(DMDestroy(&dmfo)); 9749 PetscCall(DMDestroy(&dmco)); 9750 PetscFunctionReturn(PETSC_SUCCESS); 9751 } 9752 9753 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9754 { 9755 PetscObject shifto; 9756 Vec shift; 9757 9758 PetscFunctionBegin; 9759 if (!interp) { 9760 Vec rscale; 9761 9762 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9763 PetscCall(VecDestroy(&rscale)); 9764 } else { 9765 PetscCall(PetscObjectReference((PetscObject)interp)); 9766 } 9767 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9768 if (!shifto) { 9769 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9770 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9771 shifto = (PetscObject)shift; 9772 PetscCall(VecDestroy(&shift)); 9773 } 9774 shift = (Vec)shifto; 9775 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9776 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9777 PetscCall(MatDestroy(&interp)); 9778 PetscFunctionReturn(PETSC_SUCCESS); 9779 } 9780 9781 /* Pointwise interpolation 9782 Just code FEM for now 9783 u^f = I u^c 9784 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9785 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9786 I_{ij} = psi^f_i phi^c_j 9787 */ 9788 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9789 { 9790 PetscSection gsc, gsf; 9791 PetscInt m, n; 9792 void *ctx; 9793 DM cdm; 9794 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9795 9796 PetscFunctionBegin; 9797 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9798 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9799 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9800 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9801 9802 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9803 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9804 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9805 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9806 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9807 9808 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9809 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9810 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9811 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9812 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9813 if (scaling) { 9814 /* Use naive scaling */ 9815 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9816 } 9817 PetscFunctionReturn(PETSC_SUCCESS); 9818 } 9819 9820 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9821 { 9822 VecScatter ctx; 9823 9824 PetscFunctionBegin; 9825 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9826 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9827 PetscCall(VecScatterDestroy(&ctx)); 9828 PetscFunctionReturn(PETSC_SUCCESS); 9829 } 9830 9831 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[]) 9832 { 9833 const PetscInt Nc = uOff[1] - uOff[0]; 9834 PetscInt c; 9835 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9836 } 9837 9838 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9839 { 9840 DM dmc; 9841 PetscDS ds; 9842 Vec ones, locmass; 9843 IS cellIS; 9844 PetscFormKey key; 9845 PetscInt depth; 9846 9847 PetscFunctionBegin; 9848 PetscCall(DMClone(dm, &dmc)); 9849 PetscCall(DMCopyDisc(dm, dmc)); 9850 PetscCall(DMGetDS(dmc, &ds)); 9851 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9852 PetscCall(DMCreateGlobalVector(dmc, mass)); 9853 PetscCall(DMGetLocalVector(dmc, &ones)); 9854 PetscCall(DMGetLocalVector(dmc, &locmass)); 9855 PetscCall(DMPlexGetDepth(dmc, &depth)); 9856 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9857 PetscCall(VecSet(locmass, 0.0)); 9858 PetscCall(VecSet(ones, 1.0)); 9859 key.label = NULL; 9860 key.value = 0; 9861 key.field = 0; 9862 key.part = 0; 9863 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9864 PetscCall(ISDestroy(&cellIS)); 9865 PetscCall(VecSet(*mass, 0.0)); 9866 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9867 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9868 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9869 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9870 PetscCall(DMDestroy(&dmc)); 9871 PetscFunctionReturn(PETSC_SUCCESS); 9872 } 9873 9874 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9875 { 9876 PetscSection gsc, gsf; 9877 PetscInt m, n; 9878 void *ctx; 9879 DM cdm; 9880 PetscBool regular; 9881 9882 PetscFunctionBegin; 9883 if (dmFine == dmCoarse) { 9884 DM dmc; 9885 PetscDS ds; 9886 PetscWeakForm wf; 9887 Vec u; 9888 IS cellIS; 9889 PetscFormKey key; 9890 PetscInt depth; 9891 9892 PetscCall(DMClone(dmFine, &dmc)); 9893 PetscCall(DMCopyDisc(dmFine, dmc)); 9894 PetscCall(DMGetDS(dmc, &ds)); 9895 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9896 PetscCall(PetscWeakFormClear(wf)); 9897 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9898 PetscCall(DMCreateMatrix(dmc, mass)); 9899 PetscCall(DMGetLocalVector(dmc, &u)); 9900 PetscCall(DMPlexGetDepth(dmc, &depth)); 9901 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9902 PetscCall(MatZeroEntries(*mass)); 9903 key.label = NULL; 9904 key.value = 0; 9905 key.field = 0; 9906 key.part = 0; 9907 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9908 PetscCall(ISDestroy(&cellIS)); 9909 PetscCall(DMRestoreLocalVector(dmc, &u)); 9910 PetscCall(DMDestroy(&dmc)); 9911 } else { 9912 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9913 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9914 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9915 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9916 9917 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9918 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9919 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9920 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9921 9922 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9923 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9924 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9925 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9926 } 9927 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9928 PetscFunctionReturn(PETSC_SUCCESS); 9929 } 9930 9931 /*@ 9932 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9933 9934 Input Parameter: 9935 . dm - The `DMPLEX` object 9936 9937 Output Parameter: 9938 . regular - The flag 9939 9940 Level: intermediate 9941 9942 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9943 @*/ 9944 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9945 { 9946 PetscFunctionBegin; 9947 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9948 PetscAssertPointer(regular, 2); 9949 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9950 PetscFunctionReturn(PETSC_SUCCESS); 9951 } 9952 9953 /*@ 9954 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9955 9956 Input Parameters: 9957 + dm - The `DMPLEX` object 9958 - regular - The flag 9959 9960 Level: intermediate 9961 9962 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9963 @*/ 9964 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9965 { 9966 PetscFunctionBegin; 9967 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9968 ((DM_Plex *)dm->data)->regularRefinement = regular; 9969 PetscFunctionReturn(PETSC_SUCCESS); 9970 } 9971 9972 /*@ 9973 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9974 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9975 9976 Not Collective 9977 9978 Input Parameter: 9979 . dm - The `DMPLEX` object 9980 9981 Output Parameters: 9982 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9983 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 9984 9985 Level: intermediate 9986 9987 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9988 @*/ 9989 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9990 { 9991 DM_Plex *plex = (DM_Plex *)dm->data; 9992 9993 PetscFunctionBegin; 9994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9995 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9996 if (anchorSection) *anchorSection = plex->anchorSection; 9997 if (anchorIS) *anchorIS = plex->anchorIS; 9998 PetscFunctionReturn(PETSC_SUCCESS); 9999 } 10000 10001 /*@ 10002 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10003 10004 Collective 10005 10006 Input Parameters: 10007 + dm - The `DMPLEX` object 10008 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10009 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10010 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10011 10012 Level: intermediate 10013 10014 Notes: 10015 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10016 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10017 combination of other points' degrees of freedom. 10018 10019 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10020 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10021 10022 The reference counts of `anchorSection` and `anchorIS` are incremented. 10023 10024 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10025 @*/ 10026 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10027 { 10028 DM_Plex *plex = (DM_Plex *)dm->data; 10029 PetscMPIInt result; 10030 10031 PetscFunctionBegin; 10032 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10033 if (anchorSection) { 10034 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10035 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10036 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10037 } 10038 if (anchorIS) { 10039 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10040 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10041 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10042 } 10043 10044 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10045 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10046 plex->anchorSection = anchorSection; 10047 10048 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10049 PetscCall(ISDestroy(&plex->anchorIS)); 10050 plex->anchorIS = anchorIS; 10051 10052 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10053 PetscInt size, a, pStart, pEnd; 10054 const PetscInt *anchors; 10055 10056 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10057 PetscCall(ISGetLocalSize(anchorIS, &size)); 10058 PetscCall(ISGetIndices(anchorIS, &anchors)); 10059 for (a = 0; a < size; a++) { 10060 PetscInt p; 10061 10062 p = anchors[a]; 10063 if (p >= pStart && p < pEnd) { 10064 PetscInt dof; 10065 10066 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10067 if (dof) { 10068 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10069 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10070 } 10071 } 10072 } 10073 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10074 } 10075 /* reset the generic constraints */ 10076 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10077 PetscFunctionReturn(PETSC_SUCCESS); 10078 } 10079 10080 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10081 { 10082 PetscSection anchorSection; 10083 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10084 10085 PetscFunctionBegin; 10086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10087 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10088 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10089 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10090 if (numFields) { 10091 PetscInt f; 10092 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10093 10094 for (f = 0; f < numFields; f++) { 10095 PetscInt numComp; 10096 10097 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10098 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10099 } 10100 } 10101 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10102 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10103 pStart = PetscMax(pStart, sStart); 10104 pEnd = PetscMin(pEnd, sEnd); 10105 pEnd = PetscMax(pStart, pEnd); 10106 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10107 for (p = pStart; p < pEnd; p++) { 10108 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10109 if (dof) { 10110 PetscCall(PetscSectionGetDof(section, p, &dof)); 10111 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10112 for (f = 0; f < numFields; f++) { 10113 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10114 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10115 } 10116 } 10117 } 10118 PetscCall(PetscSectionSetUp(*cSec)); 10119 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10120 PetscFunctionReturn(PETSC_SUCCESS); 10121 } 10122 10123 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10124 { 10125 PetscSection aSec; 10126 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10127 const PetscInt *anchors; 10128 PetscInt numFields, f; 10129 IS aIS; 10130 MatType mtype; 10131 PetscBool iscuda, iskokkos; 10132 10133 PetscFunctionBegin; 10134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10135 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10136 PetscCall(PetscSectionGetStorageSize(section, &n)); 10137 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10138 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10139 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10140 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10141 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10142 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10143 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10144 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10145 else mtype = MATSEQAIJ; 10146 PetscCall(MatSetType(*cMat, mtype)); 10147 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10148 PetscCall(ISGetIndices(aIS, &anchors)); 10149 /* cSec will be a subset of aSec and section */ 10150 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10151 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10152 PetscCall(PetscMalloc1(m + 1, &i)); 10153 i[0] = 0; 10154 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10155 for (p = pStart; p < pEnd; p++) { 10156 PetscInt rDof, rOff, r; 10157 10158 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10159 if (!rDof) continue; 10160 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10161 if (numFields) { 10162 for (f = 0; f < numFields; f++) { 10163 annz = 0; 10164 for (r = 0; r < rDof; r++) { 10165 a = anchors[rOff + r]; 10166 if (a < sStart || a >= sEnd) continue; 10167 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10168 annz += aDof; 10169 } 10170 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10171 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10172 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10173 } 10174 } else { 10175 annz = 0; 10176 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10177 for (q = 0; q < dof; q++) { 10178 a = anchors[rOff + q]; 10179 if (a < sStart || a >= sEnd) continue; 10180 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10181 annz += aDof; 10182 } 10183 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10184 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10185 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10186 } 10187 } 10188 nnz = i[m]; 10189 PetscCall(PetscMalloc1(nnz, &j)); 10190 offset = 0; 10191 for (p = pStart; p < pEnd; p++) { 10192 if (numFields) { 10193 for (f = 0; f < numFields; f++) { 10194 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10195 for (q = 0; q < dof; q++) { 10196 PetscInt rDof, rOff, r; 10197 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10198 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10199 for (r = 0; r < rDof; r++) { 10200 PetscInt s; 10201 10202 a = anchors[rOff + r]; 10203 if (a < sStart || a >= sEnd) continue; 10204 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10205 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10206 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10207 } 10208 } 10209 } 10210 } else { 10211 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10212 for (q = 0; q < dof; q++) { 10213 PetscInt rDof, rOff, r; 10214 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10215 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10216 for (r = 0; r < rDof; r++) { 10217 PetscInt s; 10218 10219 a = anchors[rOff + r]; 10220 if (a < sStart || a >= sEnd) continue; 10221 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10222 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10223 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10224 } 10225 } 10226 } 10227 } 10228 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10229 PetscCall(PetscFree(i)); 10230 PetscCall(PetscFree(j)); 10231 PetscCall(ISRestoreIndices(aIS, &anchors)); 10232 PetscFunctionReturn(PETSC_SUCCESS); 10233 } 10234 10235 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10236 { 10237 DM_Plex *plex = (DM_Plex *)dm->data; 10238 PetscSection anchorSection, section, cSec; 10239 Mat cMat; 10240 10241 PetscFunctionBegin; 10242 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10243 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10244 if (anchorSection) { 10245 PetscInt Nf; 10246 10247 PetscCall(DMGetLocalSection(dm, §ion)); 10248 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10249 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10250 PetscCall(DMGetNumFields(dm, &Nf)); 10251 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10252 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10253 PetscCall(PetscSectionDestroy(&cSec)); 10254 PetscCall(MatDestroy(&cMat)); 10255 } 10256 PetscFunctionReturn(PETSC_SUCCESS); 10257 } 10258 10259 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10260 { 10261 IS subis; 10262 PetscSection section, subsection; 10263 10264 PetscFunctionBegin; 10265 PetscCall(DMGetLocalSection(dm, §ion)); 10266 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10267 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10268 /* Create subdomain */ 10269 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10270 /* Create submodel */ 10271 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10272 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10273 PetscCall(DMSetLocalSection(*subdm, subsection)); 10274 PetscCall(PetscSectionDestroy(&subsection)); 10275 PetscCall(DMCopyDisc(dm, *subdm)); 10276 /* Create map from submodel to global model */ 10277 if (is) { 10278 PetscSection sectionGlobal, subsectionGlobal; 10279 IS spIS; 10280 const PetscInt *spmap; 10281 PetscInt *subIndices; 10282 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10283 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10284 10285 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10286 PetscCall(ISGetIndices(spIS, &spmap)); 10287 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10288 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10289 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10290 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10291 for (p = pStart; p < pEnd; ++p) { 10292 PetscInt gdof, pSubSize = 0; 10293 10294 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10295 if (gdof > 0) { 10296 for (f = 0; f < Nf; ++f) { 10297 PetscInt fdof, fcdof; 10298 10299 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10300 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10301 pSubSize += fdof - fcdof; 10302 } 10303 subSize += pSubSize; 10304 if (pSubSize) { 10305 if (bs < 0) { 10306 bs = pSubSize; 10307 } else if (bs != pSubSize) { 10308 /* Layout does not admit a pointwise block size */ 10309 bs = 1; 10310 } 10311 } 10312 } 10313 } 10314 /* Must have same blocksize on all procs (some might have no points) */ 10315 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10316 bsLocal[1] = bs; 10317 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10318 if (bsMinMax[0] != bsMinMax[1]) { 10319 bs = 1; 10320 } else { 10321 bs = bsMinMax[0]; 10322 } 10323 PetscCall(PetscMalloc1(subSize, &subIndices)); 10324 for (p = pStart; p < pEnd; ++p) { 10325 PetscInt gdof, goff; 10326 10327 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10328 if (gdof > 0) { 10329 const PetscInt point = spmap[p]; 10330 10331 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10332 for (f = 0; f < Nf; ++f) { 10333 PetscInt fdof, fcdof, fc, f2, poff = 0; 10334 10335 /* Can get rid of this loop by storing field information in the global section */ 10336 for (f2 = 0; f2 < f; ++f2) { 10337 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10338 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10339 poff += fdof - fcdof; 10340 } 10341 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10342 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10343 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10344 } 10345 } 10346 } 10347 PetscCall(ISRestoreIndices(spIS, &spmap)); 10348 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10349 if (bs > 1) { 10350 /* We need to check that the block size does not come from non-contiguous fields */ 10351 PetscInt i, j, set = 1; 10352 for (i = 0; i < subSize; i += bs) { 10353 for (j = 0; j < bs; ++j) { 10354 if (subIndices[i + j] != subIndices[i] + j) { 10355 set = 0; 10356 break; 10357 } 10358 } 10359 } 10360 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10361 } 10362 /* Attach nullspace */ 10363 for (f = 0; f < Nf; ++f) { 10364 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10365 if ((*subdm)->nullspaceConstructors[f]) break; 10366 } 10367 if (f < Nf) { 10368 MatNullSpace nullSpace; 10369 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10370 10371 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10372 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10373 } 10374 } 10375 PetscFunctionReturn(PETSC_SUCCESS); 10376 } 10377 10378 /*@ 10379 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10380 10381 Input Parameters: 10382 + dm - The `DM` 10383 - dummy - unused argument 10384 10385 Options Database Key: 10386 . -dm_plex_monitor_throughput - Activate the monitor 10387 10388 Level: developer 10389 10390 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10391 @*/ 10392 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10393 { 10394 PetscLogHandler default_handler; 10395 10396 PetscFunctionBegin; 10397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10398 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10399 if (default_handler) { 10400 PetscLogEvent event; 10401 PetscEventPerfInfo eventInfo; 10402 PetscReal cellRate, flopRate; 10403 PetscInt cStart, cEnd, Nf, N; 10404 const char *name; 10405 10406 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10407 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10408 PetscCall(DMGetNumFields(dm, &Nf)); 10409 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10410 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10411 N = (cEnd - cStart) * Nf * eventInfo.count; 10412 flopRate = eventInfo.flops / eventInfo.time; 10413 cellRate = N / eventInfo.time; 10414 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, (double)cellRate, (double)(flopRate / 1.e6))); 10415 } else { 10416 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."); 10417 } 10418 PetscFunctionReturn(PETSC_SUCCESS); 10419 } 10420