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 #if defined(PETSC_HAVE_EXODUSII) 1852 #include <exodusII.h> 1853 #include <petscviewerexodusii.h> 1854 #endif 1855 1856 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1857 { 1858 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1859 char name[PETSC_MAX_PATH_LEN]; 1860 1861 PetscFunctionBegin; 1862 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1863 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1864 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1865 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1866 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1867 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1868 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1869 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1870 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1871 if (iascii) { 1872 PetscViewerFormat format; 1873 PetscCall(PetscViewerGetFormat(viewer, &format)); 1874 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1875 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1876 } else if (ishdf5) { 1877 #if defined(PETSC_HAVE_HDF5) 1878 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1879 #else 1880 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1881 #endif 1882 } else if (isvtk) { 1883 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1884 } else if (isdraw) { 1885 PetscCall(DMPlexView_Draw(dm, viewer)); 1886 } else if (isglvis) { 1887 PetscCall(DMPlexView_GLVis(dm, viewer)); 1888 #if defined(PETSC_HAVE_EXODUSII) 1889 } else if (isexodus) { 1890 /* 1891 exodusII requires that all sets be part of exactly one cell set. 1892 If the dm does not have a "Cell Sets" label defined, we create one 1893 with ID 1, containing all cells. 1894 Note that if the Cell Sets label is defined but does not cover all cells, 1895 we may still have a problem. This should probably be checked here or in the viewer; 1896 */ 1897 PetscInt numCS; 1898 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1899 if (!numCS) { 1900 PetscInt cStart, cEnd, c; 1901 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1902 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1903 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1904 } 1905 PetscCall(DMView_PlexExodusII(dm, viewer)); 1906 #endif 1907 #if defined(PETSC_HAVE_CGNS) 1908 } else if (iscgns) { 1909 PetscCall(DMView_PlexCGNS(dm, viewer)); 1910 #endif 1911 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1912 /* Optionally view the partition */ 1913 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1914 if (flg) { 1915 Vec ranks; 1916 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1917 PetscCall(VecView(ranks, viewer)); 1918 PetscCall(VecDestroy(&ranks)); 1919 } 1920 /* Optionally view a label */ 1921 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1922 if (flg) { 1923 DMLabel label; 1924 Vec val; 1925 1926 PetscCall(DMGetLabel(dm, name, &label)); 1927 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1928 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1929 PetscCall(VecView(val, viewer)); 1930 PetscCall(VecDestroy(&val)); 1931 } 1932 PetscFunctionReturn(PETSC_SUCCESS); 1933 } 1934 1935 /*@ 1936 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1937 1938 Collective 1939 1940 Input Parameters: 1941 + dm - The `DM` whose topology is to be saved 1942 - viewer - The `PetscViewer` to save it in 1943 1944 Level: advanced 1945 1946 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1947 @*/ 1948 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1949 { 1950 PetscBool ishdf5; 1951 1952 PetscFunctionBegin; 1953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1954 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1955 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1956 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1957 if (ishdf5) { 1958 #if defined(PETSC_HAVE_HDF5) 1959 PetscViewerFormat format; 1960 PetscCall(PetscViewerGetFormat(viewer, &format)); 1961 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1962 IS globalPointNumbering; 1963 1964 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1965 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1966 PetscCall(ISDestroy(&globalPointNumbering)); 1967 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1968 #else 1969 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1970 #endif 1971 } 1972 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1973 PetscFunctionReturn(PETSC_SUCCESS); 1974 } 1975 1976 /*@ 1977 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 1978 1979 Collective 1980 1981 Input Parameters: 1982 + dm - The `DM` whose coordinates are to be saved 1983 - viewer - The `PetscViewer` for saving 1984 1985 Level: advanced 1986 1987 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 1988 @*/ 1989 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1990 { 1991 PetscBool ishdf5; 1992 1993 PetscFunctionBegin; 1994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1995 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1996 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1997 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1998 if (ishdf5) { 1999 #if defined(PETSC_HAVE_HDF5) 2000 PetscViewerFormat format; 2001 PetscCall(PetscViewerGetFormat(viewer, &format)); 2002 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2003 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2004 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2005 #else 2006 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2007 #endif 2008 } 2009 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2010 PetscFunctionReturn(PETSC_SUCCESS); 2011 } 2012 2013 /*@ 2014 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2015 2016 Collective 2017 2018 Input Parameters: 2019 + dm - The `DM` whose labels are to be saved 2020 - viewer - The `PetscViewer` for saving 2021 2022 Level: advanced 2023 2024 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2025 @*/ 2026 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2027 { 2028 PetscBool ishdf5; 2029 2030 PetscFunctionBegin; 2031 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2032 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2033 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2034 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2035 if (ishdf5) { 2036 #if defined(PETSC_HAVE_HDF5) 2037 IS globalPointNumbering; 2038 PetscViewerFormat format; 2039 2040 PetscCall(PetscViewerGetFormat(viewer, &format)); 2041 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2042 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2043 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2044 PetscCall(ISDestroy(&globalPointNumbering)); 2045 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2046 #else 2047 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2048 #endif 2049 } 2050 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2051 PetscFunctionReturn(PETSC_SUCCESS); 2052 } 2053 2054 /*@ 2055 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2056 2057 Collective 2058 2059 Input Parameters: 2060 + dm - The `DM` that contains the topology on which the section to be saved is defined 2061 . viewer - The `PetscViewer` for saving 2062 - sectiondm - The `DM` that contains the section to be saved 2063 2064 Level: advanced 2065 2066 Notes: 2067 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. 2068 2069 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. 2070 2071 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2072 @*/ 2073 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2074 { 2075 PetscBool ishdf5; 2076 2077 PetscFunctionBegin; 2078 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2079 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2080 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2081 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2082 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2083 if (ishdf5) { 2084 #if defined(PETSC_HAVE_HDF5) 2085 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2086 #else 2087 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2088 #endif 2089 } 2090 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2091 PetscFunctionReturn(PETSC_SUCCESS); 2092 } 2093 2094 /*@ 2095 DMPlexGlobalVectorView - Saves a global vector 2096 2097 Collective 2098 2099 Input Parameters: 2100 + dm - The `DM` that represents the topology 2101 . viewer - The `PetscViewer` to save data with 2102 . sectiondm - The `DM` that contains the global section on which vec is defined 2103 - vec - The global vector to be saved 2104 2105 Level: advanced 2106 2107 Notes: 2108 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. 2109 2110 Calling sequence: 2111 .vb 2112 DMCreate(PETSC_COMM_WORLD, &dm); 2113 DMSetType(dm, DMPLEX); 2114 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2115 DMClone(dm, §iondm); 2116 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2117 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2118 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2119 PetscSectionSetChart(section, pStart, pEnd); 2120 PetscSectionSetUp(section); 2121 DMSetLocalSection(sectiondm, section); 2122 PetscSectionDestroy(§ion); 2123 DMGetGlobalVector(sectiondm, &vec); 2124 PetscObjectSetName((PetscObject)vec, "vec_name"); 2125 DMPlexTopologyView(dm, viewer); 2126 DMPlexSectionView(dm, viewer, sectiondm); 2127 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2128 DMRestoreGlobalVector(sectiondm, &vec); 2129 DMDestroy(§iondm); 2130 DMDestroy(&dm); 2131 .ve 2132 2133 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2134 @*/ 2135 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2136 { 2137 PetscBool ishdf5; 2138 2139 PetscFunctionBegin; 2140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2141 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2142 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2143 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2144 /* Check consistency */ 2145 { 2146 PetscSection section; 2147 PetscBool includesConstraints; 2148 PetscInt m, m1; 2149 2150 PetscCall(VecGetLocalSize(vec, &m1)); 2151 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2152 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2153 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2154 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2155 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2156 } 2157 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2158 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2159 if (ishdf5) { 2160 #if defined(PETSC_HAVE_HDF5) 2161 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2162 #else 2163 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2164 #endif 2165 } 2166 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2167 PetscFunctionReturn(PETSC_SUCCESS); 2168 } 2169 2170 /*@ 2171 DMPlexLocalVectorView - Saves a local vector 2172 2173 Collective 2174 2175 Input Parameters: 2176 + dm - The `DM` that represents the topology 2177 . viewer - The `PetscViewer` to save data with 2178 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2179 - vec - The local vector to be saved 2180 2181 Level: advanced 2182 2183 Note: 2184 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. 2185 2186 Calling sequence: 2187 .vb 2188 DMCreate(PETSC_COMM_WORLD, &dm); 2189 DMSetType(dm, DMPLEX); 2190 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2191 DMClone(dm, §iondm); 2192 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2193 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2194 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2195 PetscSectionSetChart(section, pStart, pEnd); 2196 PetscSectionSetUp(section); 2197 DMSetLocalSection(sectiondm, section); 2198 DMGetLocalVector(sectiondm, &vec); 2199 PetscObjectSetName((PetscObject)vec, "vec_name"); 2200 DMPlexTopologyView(dm, viewer); 2201 DMPlexSectionView(dm, viewer, sectiondm); 2202 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2203 DMRestoreLocalVector(sectiondm, &vec); 2204 DMDestroy(§iondm); 2205 DMDestroy(&dm); 2206 .ve 2207 2208 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2209 @*/ 2210 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2211 { 2212 PetscBool ishdf5; 2213 2214 PetscFunctionBegin; 2215 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2216 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2217 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2218 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2219 /* Check consistency */ 2220 { 2221 PetscSection section; 2222 PetscBool includesConstraints; 2223 PetscInt m, m1; 2224 2225 PetscCall(VecGetLocalSize(vec, &m1)); 2226 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2227 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2228 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2229 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2230 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2231 } 2232 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2233 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2234 if (ishdf5) { 2235 #if defined(PETSC_HAVE_HDF5) 2236 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2237 #else 2238 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2239 #endif 2240 } 2241 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2242 PetscFunctionReturn(PETSC_SUCCESS); 2243 } 2244 2245 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2246 { 2247 PetscBool ishdf5; 2248 2249 PetscFunctionBegin; 2250 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2251 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2252 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2253 if (ishdf5) { 2254 #if defined(PETSC_HAVE_HDF5) 2255 PetscViewerFormat format; 2256 PetscCall(PetscViewerGetFormat(viewer, &format)); 2257 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2258 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2259 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2260 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2261 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2262 PetscFunctionReturn(PETSC_SUCCESS); 2263 #else 2264 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2265 #endif 2266 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2267 } 2268 2269 /*@ 2270 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2271 2272 Collective 2273 2274 Input Parameters: 2275 + dm - The `DM` into which the topology is loaded 2276 - viewer - The `PetscViewer` for the saved topology 2277 2278 Output Parameter: 2279 . 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 2280 2281 Level: advanced 2282 2283 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2284 `PetscViewer`, `PetscSF` 2285 @*/ 2286 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2287 { 2288 PetscBool ishdf5; 2289 2290 PetscFunctionBegin; 2291 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2292 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2293 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2294 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2295 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2296 if (ishdf5) { 2297 #if defined(PETSC_HAVE_HDF5) 2298 PetscViewerFormat format; 2299 PetscCall(PetscViewerGetFormat(viewer, &format)); 2300 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2301 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2302 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2303 #else 2304 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2305 #endif 2306 } 2307 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2308 PetscFunctionReturn(PETSC_SUCCESS); 2309 } 2310 2311 /*@ 2312 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2313 2314 Collective 2315 2316 Input Parameters: 2317 + dm - The `DM` into which the coordinates are loaded 2318 . viewer - The `PetscViewer` for the saved coordinates 2319 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2320 2321 Level: advanced 2322 2323 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2324 `PetscSF`, `PetscViewer` 2325 @*/ 2326 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2327 { 2328 PetscBool ishdf5; 2329 2330 PetscFunctionBegin; 2331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2332 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2333 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2334 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2335 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2336 if (ishdf5) { 2337 #if defined(PETSC_HAVE_HDF5) 2338 PetscViewerFormat format; 2339 PetscCall(PetscViewerGetFormat(viewer, &format)); 2340 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2341 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2342 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2343 #else 2344 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2345 #endif 2346 } 2347 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2348 PetscFunctionReturn(PETSC_SUCCESS); 2349 } 2350 2351 /*@ 2352 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2353 2354 Collective 2355 2356 Input Parameters: 2357 + dm - The `DM` into which the labels are loaded 2358 . viewer - The `PetscViewer` for the saved labels 2359 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2360 2361 Level: advanced 2362 2363 Note: 2364 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2365 2366 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2367 `PetscSF`, `PetscViewer` 2368 @*/ 2369 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2370 { 2371 PetscBool ishdf5; 2372 2373 PetscFunctionBegin; 2374 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2375 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2376 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2377 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2378 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2379 if (ishdf5) { 2380 #if defined(PETSC_HAVE_HDF5) 2381 PetscViewerFormat format; 2382 2383 PetscCall(PetscViewerGetFormat(viewer, &format)); 2384 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2385 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2386 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2387 #else 2388 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2389 #endif 2390 } 2391 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2392 PetscFunctionReturn(PETSC_SUCCESS); 2393 } 2394 2395 /*@ 2396 DMPlexSectionLoad - Loads section into a `DMPLEX` 2397 2398 Collective 2399 2400 Input Parameters: 2401 + dm - The `DM` that represents the topology 2402 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2403 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2404 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2405 2406 Output Parameters: 2407 + 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) 2408 - 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) 2409 2410 Level: advanced 2411 2412 Notes: 2413 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. 2414 2415 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. 2416 2417 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. 2418 2419 Example using 2 processes: 2420 .vb 2421 NX (number of points on dm): 4 2422 sectionA : the on-disk section 2423 vecA : a vector associated with sectionA 2424 sectionB : sectiondm's local section constructed in this function 2425 vecB (local) : a vector associated with sectiondm's local section 2426 vecB (global) : a vector associated with sectiondm's global section 2427 2428 rank 0 rank 1 2429 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2430 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2431 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2432 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2433 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2434 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2435 sectionB->atlasDof : 1 0 1 | 1 3 2436 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2437 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2438 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2439 .ve 2440 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2441 2442 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2443 @*/ 2444 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2445 { 2446 PetscBool ishdf5; 2447 2448 PetscFunctionBegin; 2449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2450 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2451 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2452 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2453 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2454 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2455 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2456 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2457 if (ishdf5) { 2458 #if defined(PETSC_HAVE_HDF5) 2459 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2460 #else 2461 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2462 #endif 2463 } 2464 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2465 PetscFunctionReturn(PETSC_SUCCESS); 2466 } 2467 2468 /*@ 2469 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2470 2471 Collective 2472 2473 Input Parameters: 2474 + dm - The `DM` that represents the topology 2475 . viewer - The `PetscViewer` that represents the on-disk vector data 2476 . sectiondm - The `DM` that contains the global section on which vec is defined 2477 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2478 - vec - The global vector to set values of 2479 2480 Level: advanced 2481 2482 Notes: 2483 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. 2484 2485 Calling sequence: 2486 .vb 2487 DMCreate(PETSC_COMM_WORLD, &dm); 2488 DMSetType(dm, DMPLEX); 2489 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2490 DMPlexTopologyLoad(dm, viewer, &sfX); 2491 DMClone(dm, §iondm); 2492 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2493 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2494 DMGetGlobalVector(sectiondm, &vec); 2495 PetscObjectSetName((PetscObject)vec, "vec_name"); 2496 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2497 DMRestoreGlobalVector(sectiondm, &vec); 2498 PetscSFDestroy(&gsf); 2499 PetscSFDestroy(&sfX); 2500 DMDestroy(§iondm); 2501 DMDestroy(&dm); 2502 .ve 2503 2504 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2505 `PetscSF`, `PetscViewer` 2506 @*/ 2507 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2508 { 2509 PetscBool ishdf5; 2510 2511 PetscFunctionBegin; 2512 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2513 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2514 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2515 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2516 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2517 /* Check consistency */ 2518 { 2519 PetscSection section; 2520 PetscBool includesConstraints; 2521 PetscInt m, m1; 2522 2523 PetscCall(VecGetLocalSize(vec, &m1)); 2524 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2525 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2526 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2527 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2528 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2529 } 2530 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2531 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2532 if (ishdf5) { 2533 #if defined(PETSC_HAVE_HDF5) 2534 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2535 #else 2536 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2537 #endif 2538 } 2539 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2540 PetscFunctionReturn(PETSC_SUCCESS); 2541 } 2542 2543 /*@ 2544 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2545 2546 Collective 2547 2548 Input Parameters: 2549 + dm - The `DM` that represents the topology 2550 . viewer - The `PetscViewer` that represents the on-disk vector data 2551 . sectiondm - The `DM` that contains the local section on which vec is defined 2552 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2553 - vec - The local vector to set values of 2554 2555 Level: advanced 2556 2557 Notes: 2558 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. 2559 2560 Calling sequence: 2561 .vb 2562 DMCreate(PETSC_COMM_WORLD, &dm); 2563 DMSetType(dm, DMPLEX); 2564 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2565 DMPlexTopologyLoad(dm, viewer, &sfX); 2566 DMClone(dm, §iondm); 2567 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2568 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2569 DMGetLocalVector(sectiondm, &vec); 2570 PetscObjectSetName((PetscObject)vec, "vec_name"); 2571 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2572 DMRestoreLocalVector(sectiondm, &vec); 2573 PetscSFDestroy(&lsf); 2574 PetscSFDestroy(&sfX); 2575 DMDestroy(§iondm); 2576 DMDestroy(&dm); 2577 .ve 2578 2579 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2580 `PetscSF`, `PetscViewer` 2581 @*/ 2582 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2583 { 2584 PetscBool ishdf5; 2585 2586 PetscFunctionBegin; 2587 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2588 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2589 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2590 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2591 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2592 /* Check consistency */ 2593 { 2594 PetscSection section; 2595 PetscBool includesConstraints; 2596 PetscInt m, m1; 2597 2598 PetscCall(VecGetLocalSize(vec, &m1)); 2599 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2600 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2601 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2602 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2603 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2604 } 2605 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2606 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2607 if (ishdf5) { 2608 #if defined(PETSC_HAVE_HDF5) 2609 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2610 #else 2611 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2612 #endif 2613 } 2614 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2615 PetscFunctionReturn(PETSC_SUCCESS); 2616 } 2617 2618 PetscErrorCode DMDestroy_Plex(DM dm) 2619 { 2620 DM_Plex *mesh = (DM_Plex *)dm->data; 2621 2622 PetscFunctionBegin; 2623 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2624 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2625 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2626 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2627 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2628 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2629 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2630 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2631 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2632 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2633 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2634 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2635 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2636 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2637 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2638 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2639 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2640 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2641 PetscCall(PetscFree(mesh->cones)); 2642 PetscCall(PetscFree(mesh->coneOrientations)); 2643 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2644 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2645 PetscCall(PetscFree(mesh->supports)); 2646 PetscCall(PetscFree(mesh->cellTypes)); 2647 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2648 PetscCall(PetscFree(mesh->tetgenOpts)); 2649 PetscCall(PetscFree(mesh->triangleOpts)); 2650 PetscCall(PetscFree(mesh->transformType)); 2651 PetscCall(PetscFree(mesh->distributionName)); 2652 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2653 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2654 PetscCall(ISDestroy(&mesh->subpointIS)); 2655 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2656 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2657 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2658 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2659 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2660 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2661 PetscCall(ISDestroy(&mesh->anchorIS)); 2662 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2663 PetscCall(PetscFree(mesh->parents)); 2664 PetscCall(PetscFree(mesh->childIDs)); 2665 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2666 PetscCall(PetscFree(mesh->children)); 2667 PetscCall(DMDestroy(&mesh->referenceTree)); 2668 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2669 PetscCall(PetscFree(mesh->neighbors)); 2670 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2671 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2672 PetscCall(PetscFree(mesh)); 2673 PetscFunctionReturn(PETSC_SUCCESS); 2674 } 2675 2676 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2677 { 2678 PetscSection sectionGlobal; 2679 PetscInt bs = -1, mbs; 2680 PetscInt localSize, localStart = 0; 2681 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2682 MatType mtype; 2683 ISLocalToGlobalMapping ltog; 2684 2685 PetscFunctionBegin; 2686 PetscCall(MatInitializePackage()); 2687 mtype = dm->mattype; 2688 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2689 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2690 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2691 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2692 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2693 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2694 PetscCall(MatSetType(*J, mtype)); 2695 PetscCall(MatSetFromOptions(*J)); 2696 PetscCall(MatGetBlockSize(*J, &mbs)); 2697 if (mbs > 1) bs = mbs; 2698 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2699 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2700 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2701 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2702 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2703 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2704 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2705 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2706 if (!isShell) { 2707 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2708 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2709 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2710 2711 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2712 2713 PetscCall(PetscCalloc1(localSize, &pblocks)); 2714 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2715 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2716 for (p = pStart; p < pEnd; ++p) { 2717 switch (dm->blocking_type) { 2718 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2719 PetscInt bdof, offset; 2720 2721 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2722 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2723 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2724 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2725 dof = dof < 0 ? -(dof + 1) : dof; 2726 bdof = cdof && (dof - cdof) ? 1 : dof; 2727 if (dof) { 2728 if (bs < 0) { 2729 bs = bdof; 2730 } else if (bs != bdof) { 2731 bs = 1; 2732 } 2733 } 2734 } break; 2735 case DM_BLOCKING_FIELD_NODE: { 2736 for (PetscInt field = 0; field < num_fields; field++) { 2737 PetscInt num_comp, bdof, offset; 2738 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2739 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2740 if (dof < 0) continue; 2741 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2742 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2743 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); 2744 PetscInt num_nodes = dof / num_comp; 2745 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2746 // Handle possibly constant block size (unlikely) 2747 bdof = cdof && (dof - cdof) ? 1 : dof; 2748 if (dof) { 2749 if (bs < 0) { 2750 bs = bdof; 2751 } else if (bs != bdof) { 2752 bs = 1; 2753 } 2754 } 2755 } 2756 } break; 2757 } 2758 } 2759 /* Must have same blocksize on all procs (some might have no points) */ 2760 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2761 bsLocal[1] = bs; 2762 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2763 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2764 else bs = bsMinMax[0]; 2765 bs = PetscMax(1, bs); 2766 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2767 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2768 PetscCall(MatSetBlockSize(*J, bs)); 2769 PetscCall(MatSetUp(*J)); 2770 } else { 2771 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2772 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2773 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2774 } 2775 { // Consolidate blocks 2776 PetscInt nblocks = 0; 2777 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2778 if (pblocks[i] == 0) continue; 2779 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2780 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]); 2781 } 2782 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2783 } 2784 PetscCall(PetscFree(pblocks)); 2785 } 2786 PetscCall(MatSetDM(*J, dm)); 2787 PetscFunctionReturn(PETSC_SUCCESS); 2788 } 2789 2790 /*@ 2791 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2792 2793 Not Collective 2794 2795 Input Parameter: 2796 . dm - The `DMPLEX` 2797 2798 Output Parameter: 2799 . subsection - The subdomain section 2800 2801 Level: developer 2802 2803 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2804 @*/ 2805 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2806 { 2807 DM_Plex *mesh = (DM_Plex *)dm->data; 2808 2809 PetscFunctionBegin; 2810 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2811 if (!mesh->subdomainSection) { 2812 PetscSection section; 2813 PetscSF sf; 2814 2815 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2816 PetscCall(DMGetLocalSection(dm, §ion)); 2817 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2818 PetscCall(PetscSFDestroy(&sf)); 2819 } 2820 *subsection = mesh->subdomainSection; 2821 PetscFunctionReturn(PETSC_SUCCESS); 2822 } 2823 2824 /*@ 2825 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2826 2827 Not Collective 2828 2829 Input Parameter: 2830 . dm - The `DMPLEX` 2831 2832 Output Parameters: 2833 + pStart - The first mesh point 2834 - pEnd - The upper bound for mesh points 2835 2836 Level: beginner 2837 2838 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2839 @*/ 2840 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2841 { 2842 DM_Plex *mesh = (DM_Plex *)dm->data; 2843 2844 PetscFunctionBegin; 2845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2846 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2847 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2848 PetscFunctionReturn(PETSC_SUCCESS); 2849 } 2850 2851 /*@ 2852 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2853 2854 Not Collective 2855 2856 Input Parameters: 2857 + dm - The `DMPLEX` 2858 . pStart - The first mesh point 2859 - pEnd - The upper bound for mesh points 2860 2861 Level: beginner 2862 2863 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2864 @*/ 2865 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2866 { 2867 DM_Plex *mesh = (DM_Plex *)dm->data; 2868 2869 PetscFunctionBegin; 2870 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2871 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2872 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2873 PetscCall(PetscFree(mesh->cellTypes)); 2874 PetscFunctionReturn(PETSC_SUCCESS); 2875 } 2876 2877 /*@ 2878 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2879 2880 Not Collective 2881 2882 Input Parameters: 2883 + dm - The `DMPLEX` 2884 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2885 2886 Output Parameter: 2887 . size - The cone size for point `p` 2888 2889 Level: beginner 2890 2891 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2892 @*/ 2893 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2894 { 2895 DM_Plex *mesh = (DM_Plex *)dm->data; 2896 2897 PetscFunctionBegin; 2898 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2899 PetscAssertPointer(size, 3); 2900 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2901 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2902 PetscFunctionReturn(PETSC_SUCCESS); 2903 } 2904 2905 /*@ 2906 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2907 2908 Not Collective 2909 2910 Input Parameters: 2911 + dm - The `DMPLEX` 2912 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2913 - size - The cone size for point `p` 2914 2915 Level: beginner 2916 2917 Note: 2918 This should be called after `DMPlexSetChart()`. 2919 2920 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2921 @*/ 2922 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2923 { 2924 DM_Plex *mesh = (DM_Plex *)dm->data; 2925 2926 PetscFunctionBegin; 2927 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2928 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2929 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2930 PetscFunctionReturn(PETSC_SUCCESS); 2931 } 2932 2933 /*@C 2934 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2935 2936 Not Collective 2937 2938 Input Parameters: 2939 + dm - The `DMPLEX` 2940 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2941 2942 Output Parameter: 2943 . cone - An array of points which are on the in-edges for point `p` 2944 2945 Level: beginner 2946 2947 Fortran Notes: 2948 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2949 `DMPlexRestoreCone()` is not needed/available in C. 2950 2951 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 2952 @*/ 2953 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2954 { 2955 DM_Plex *mesh = (DM_Plex *)dm->data; 2956 PetscInt off; 2957 2958 PetscFunctionBegin; 2959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2960 PetscAssertPointer(cone, 3); 2961 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2962 *cone = &mesh->cones[off]; 2963 PetscFunctionReturn(PETSC_SUCCESS); 2964 } 2965 2966 /*@C 2967 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2968 2969 Not Collective 2970 2971 Input Parameters: 2972 + dm - The `DMPLEX` 2973 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2974 2975 Output Parameters: 2976 + pConesSection - `PetscSection` describing the layout of `pCones` 2977 - pCones - An array of points which are on the in-edges for the point set `p` 2978 2979 Level: intermediate 2980 2981 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 2982 @*/ 2983 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2984 { 2985 PetscSection cs, newcs; 2986 PetscInt *cones; 2987 PetscInt *newarr = NULL; 2988 PetscInt n; 2989 2990 PetscFunctionBegin; 2991 PetscCall(DMPlexGetCones(dm, &cones)); 2992 PetscCall(DMPlexGetConeSection(dm, &cs)); 2993 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2994 if (pConesSection) *pConesSection = newcs; 2995 if (pCones) { 2996 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2997 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2998 } 2999 PetscFunctionReturn(PETSC_SUCCESS); 3000 } 3001 3002 /*@ 3003 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3004 3005 Not Collective 3006 3007 Input Parameters: 3008 + dm - The `DMPLEX` 3009 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3010 3011 Output Parameter: 3012 . expandedPoints - An array of vertices recursively expanded from input points 3013 3014 Level: advanced 3015 3016 Notes: 3017 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3018 3019 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3020 3021 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3022 `DMPlexGetDepth()`, `IS` 3023 @*/ 3024 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3025 { 3026 IS *expandedPointsAll; 3027 PetscInt depth; 3028 3029 PetscFunctionBegin; 3030 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3031 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3032 PetscAssertPointer(expandedPoints, 3); 3033 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3034 *expandedPoints = expandedPointsAll[0]; 3035 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3036 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3037 PetscFunctionReturn(PETSC_SUCCESS); 3038 } 3039 3040 /*@ 3041 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). 3042 3043 Not Collective 3044 3045 Input Parameters: 3046 + dm - The `DMPLEX` 3047 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3048 3049 Output Parameters: 3050 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3051 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3052 - sections - (optional) An array of sections which describe mappings from points to their cone points 3053 3054 Level: advanced 3055 3056 Notes: 3057 Like `DMPlexGetConeTuple()` but recursive. 3058 3059 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. 3060 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3061 3062 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\: 3063 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3064 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3065 3066 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3067 `DMPlexGetDepth()`, `PetscSection`, `IS` 3068 @*/ 3069 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3070 { 3071 const PetscInt *arr0 = NULL, *cone = NULL; 3072 PetscInt *arr = NULL, *newarr = NULL; 3073 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3074 IS *expandedPoints_; 3075 PetscSection *sections_; 3076 3077 PetscFunctionBegin; 3078 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3079 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3080 if (depth) PetscAssertPointer(depth, 3); 3081 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3082 if (sections) PetscAssertPointer(sections, 5); 3083 PetscCall(ISGetLocalSize(points, &n)); 3084 PetscCall(ISGetIndices(points, &arr0)); 3085 PetscCall(DMPlexGetDepth(dm, &depth_)); 3086 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3087 PetscCall(PetscCalloc1(depth_, §ions_)); 3088 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3089 for (d = depth_ - 1; d >= 0; d--) { 3090 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3091 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3092 for (i = 0; i < n; i++) { 3093 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3094 if (arr[i] >= start && arr[i] < end) { 3095 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3096 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3097 } else { 3098 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3099 } 3100 } 3101 PetscCall(PetscSectionSetUp(sections_[d])); 3102 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3103 PetscCall(PetscMalloc1(newn, &newarr)); 3104 for (i = 0; i < n; i++) { 3105 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3106 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3107 if (cn > 1) { 3108 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3109 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3110 } else { 3111 newarr[co] = arr[i]; 3112 } 3113 } 3114 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3115 arr = newarr; 3116 n = newn; 3117 } 3118 PetscCall(ISRestoreIndices(points, &arr0)); 3119 *depth = depth_; 3120 if (expandedPoints) *expandedPoints = expandedPoints_; 3121 else { 3122 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3123 PetscCall(PetscFree(expandedPoints_)); 3124 } 3125 if (sections) *sections = sections_; 3126 else { 3127 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3128 PetscCall(PetscFree(sections_)); 3129 } 3130 PetscFunctionReturn(PETSC_SUCCESS); 3131 } 3132 3133 /*@ 3134 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3135 3136 Not Collective 3137 3138 Input Parameters: 3139 + dm - The `DMPLEX` 3140 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3141 3142 Output Parameters: 3143 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3144 . expandedPoints - (optional) An array of recursively expanded cones 3145 - sections - (optional) An array of sections which describe mappings from points to their cone points 3146 3147 Level: advanced 3148 3149 Note: 3150 See `DMPlexGetConeRecursive()` 3151 3152 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3153 `DMPlexGetDepth()`, `IS`, `PetscSection` 3154 @*/ 3155 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3156 { 3157 PetscInt d, depth_; 3158 3159 PetscFunctionBegin; 3160 PetscCall(DMPlexGetDepth(dm, &depth_)); 3161 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3162 if (depth) *depth = 0; 3163 if (expandedPoints) { 3164 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3165 PetscCall(PetscFree(*expandedPoints)); 3166 } 3167 if (sections) { 3168 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3169 PetscCall(PetscFree(*sections)); 3170 } 3171 PetscFunctionReturn(PETSC_SUCCESS); 3172 } 3173 3174 /*@ 3175 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 3176 3177 Not Collective 3178 3179 Input Parameters: 3180 + dm - The `DMPLEX` 3181 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3182 - cone - An array of points which are on the in-edges for point `p` 3183 3184 Level: beginner 3185 3186 Note: 3187 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3188 3189 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3190 @*/ 3191 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3192 { 3193 DM_Plex *mesh = (DM_Plex *)dm->data; 3194 PetscInt dof, off, c; 3195 3196 PetscFunctionBegin; 3197 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3198 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3199 if (dof) PetscAssertPointer(cone, 3); 3200 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3201 if (PetscDefined(USE_DEBUG)) { 3202 PetscInt pStart, pEnd; 3203 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3204 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); 3205 for (c = 0; c < dof; ++c) { 3206 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); 3207 mesh->cones[off + c] = cone[c]; 3208 } 3209 } else { 3210 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3211 } 3212 PetscFunctionReturn(PETSC_SUCCESS); 3213 } 3214 3215 /*@C 3216 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3217 3218 Not Collective 3219 3220 Input Parameters: 3221 + dm - The `DMPLEX` 3222 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3223 3224 Output Parameter: 3225 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3226 integer giving the prescription for cone traversal. 3227 3228 Level: beginner 3229 3230 Note: 3231 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3232 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3233 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3234 with the identity. 3235 3236 Fortran Notes: 3237 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3238 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3239 3240 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3241 @*/ 3242 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3243 { 3244 DM_Plex *mesh = (DM_Plex *)dm->data; 3245 PetscInt off; 3246 3247 PetscFunctionBegin; 3248 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3249 if (PetscDefined(USE_DEBUG)) { 3250 PetscInt dof; 3251 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3252 if (dof) PetscAssertPointer(coneOrientation, 3); 3253 } 3254 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3255 3256 *coneOrientation = &mesh->coneOrientations[off]; 3257 PetscFunctionReturn(PETSC_SUCCESS); 3258 } 3259 3260 /*@ 3261 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3262 3263 Not Collective 3264 3265 Input Parameters: 3266 + dm - The `DMPLEX` 3267 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3268 - coneOrientation - An array of orientations 3269 3270 Level: beginner 3271 3272 Notes: 3273 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3274 3275 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3276 3277 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3278 @*/ 3279 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3280 { 3281 DM_Plex *mesh = (DM_Plex *)dm->data; 3282 PetscInt pStart, pEnd; 3283 PetscInt dof, off, c; 3284 3285 PetscFunctionBegin; 3286 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3287 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3288 if (dof) PetscAssertPointer(coneOrientation, 3); 3289 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3290 if (PetscDefined(USE_DEBUG)) { 3291 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3292 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); 3293 for (c = 0; c < dof; ++c) { 3294 PetscInt cdof, o = coneOrientation[c]; 3295 3296 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3297 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); 3298 mesh->coneOrientations[off + c] = o; 3299 } 3300 } else { 3301 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3302 } 3303 PetscFunctionReturn(PETSC_SUCCESS); 3304 } 3305 3306 /*@ 3307 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3308 3309 Not Collective 3310 3311 Input Parameters: 3312 + dm - The `DMPLEX` 3313 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3314 . conePos - The local index in the cone where the point should be put 3315 - conePoint - The mesh point to insert 3316 3317 Level: beginner 3318 3319 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3320 @*/ 3321 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3322 { 3323 DM_Plex *mesh = (DM_Plex *)dm->data; 3324 PetscInt pStart, pEnd; 3325 PetscInt dof, off; 3326 3327 PetscFunctionBegin; 3328 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3329 if (PetscDefined(USE_DEBUG)) { 3330 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3331 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); 3332 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); 3333 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3334 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); 3335 } 3336 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3337 mesh->cones[off + conePos] = conePoint; 3338 PetscFunctionReturn(PETSC_SUCCESS); 3339 } 3340 3341 /*@ 3342 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3343 3344 Not Collective 3345 3346 Input Parameters: 3347 + dm - The `DMPLEX` 3348 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3349 . conePos - The local index in the cone where the point should be put 3350 - coneOrientation - The point orientation to insert 3351 3352 Level: beginner 3353 3354 Note: 3355 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3356 3357 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3358 @*/ 3359 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3360 { 3361 DM_Plex *mesh = (DM_Plex *)dm->data; 3362 PetscInt pStart, pEnd; 3363 PetscInt dof, off; 3364 3365 PetscFunctionBegin; 3366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3367 if (PetscDefined(USE_DEBUG)) { 3368 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3369 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); 3370 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3371 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); 3372 } 3373 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3374 mesh->coneOrientations[off + conePos] = coneOrientation; 3375 PetscFunctionReturn(PETSC_SUCCESS); 3376 } 3377 3378 /*@C 3379 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3380 3381 Not collective 3382 3383 Input Parameters: 3384 + dm - The DMPlex 3385 - p - The point, which must lie in the chart set with DMPlexSetChart() 3386 3387 Output Parameters: 3388 + cone - An array of points which are on the in-edges for point `p` 3389 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3390 integer giving the prescription for cone traversal. 3391 3392 Level: beginner 3393 3394 Notes: 3395 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3396 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3397 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3398 with the identity. 3399 3400 Fortran Notes: 3401 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3402 `DMPlexRestoreCone()` is not needed/available in C. 3403 3404 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3405 @*/ 3406 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3407 { 3408 DM_Plex *mesh = (DM_Plex *)dm->data; 3409 3410 PetscFunctionBegin; 3411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3412 if (mesh->tr) { 3413 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3414 } else { 3415 PetscInt off; 3416 if (PetscDefined(USE_DEBUG)) { 3417 PetscInt dof; 3418 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3419 if (dof) { 3420 if (cone) PetscAssertPointer(cone, 3); 3421 if (ornt) PetscAssertPointer(ornt, 4); 3422 } 3423 } 3424 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3425 if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB 3426 if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL; 3427 } 3428 PetscFunctionReturn(PETSC_SUCCESS); 3429 } 3430 3431 /*@C 3432 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3433 3434 Not Collective 3435 3436 Input Parameters: 3437 + dm - The DMPlex 3438 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3439 . cone - An array of points which are on the in-edges for point p 3440 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3441 integer giving the prescription for cone traversal. 3442 3443 Level: beginner 3444 3445 Notes: 3446 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3447 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3448 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3449 with the identity. 3450 3451 Fortran Notes: 3452 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3453 `DMPlexRestoreCone()` is not needed/available in C. 3454 3455 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3456 @*/ 3457 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3458 { 3459 DM_Plex *mesh = (DM_Plex *)dm->data; 3460 3461 PetscFunctionBegin; 3462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3463 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3464 PetscFunctionReturn(PETSC_SUCCESS); 3465 } 3466 3467 /*@ 3468 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3469 3470 Not Collective 3471 3472 Input Parameters: 3473 + dm - The `DMPLEX` 3474 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3475 3476 Output Parameter: 3477 . size - The support size for point `p` 3478 3479 Level: beginner 3480 3481 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3482 @*/ 3483 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3484 { 3485 DM_Plex *mesh = (DM_Plex *)dm->data; 3486 3487 PetscFunctionBegin; 3488 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3489 PetscAssertPointer(size, 3); 3490 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3491 PetscFunctionReturn(PETSC_SUCCESS); 3492 } 3493 3494 /*@ 3495 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3496 3497 Not Collective 3498 3499 Input Parameters: 3500 + dm - The `DMPLEX` 3501 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3502 - size - The support size for point `p` 3503 3504 Level: beginner 3505 3506 Note: 3507 This should be called after `DMPlexSetChart()`. 3508 3509 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3510 @*/ 3511 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3512 { 3513 DM_Plex *mesh = (DM_Plex *)dm->data; 3514 3515 PetscFunctionBegin; 3516 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3517 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3518 PetscFunctionReturn(PETSC_SUCCESS); 3519 } 3520 3521 /*@C 3522 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3523 3524 Not Collective 3525 3526 Input Parameters: 3527 + dm - The `DMPLEX` 3528 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3529 3530 Output Parameter: 3531 . support - An array of points which are on the out-edges for point `p` 3532 3533 Level: beginner 3534 3535 Fortran Notes: 3536 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3537 `DMPlexRestoreSupport()` is not needed/available in C. 3538 3539 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3540 @*/ 3541 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3542 { 3543 DM_Plex *mesh = (DM_Plex *)dm->data; 3544 PetscInt off; 3545 3546 PetscFunctionBegin; 3547 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3548 PetscAssertPointer(support, 3); 3549 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3550 *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB 3551 PetscFunctionReturn(PETSC_SUCCESS); 3552 } 3553 3554 /*@ 3555 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3556 3557 Not Collective 3558 3559 Input Parameters: 3560 + dm - The `DMPLEX` 3561 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3562 - support - An array of points which are on the out-edges for point `p` 3563 3564 Level: beginner 3565 3566 Note: 3567 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3568 3569 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3570 @*/ 3571 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3572 { 3573 DM_Plex *mesh = (DM_Plex *)dm->data; 3574 PetscInt pStart, pEnd; 3575 PetscInt dof, off, c; 3576 3577 PetscFunctionBegin; 3578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3579 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3580 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3581 if (dof) PetscAssertPointer(support, 3); 3582 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3583 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); 3584 for (c = 0; c < dof; ++c) { 3585 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); 3586 mesh->supports[off + c] = support[c]; 3587 } 3588 PetscFunctionReturn(PETSC_SUCCESS); 3589 } 3590 3591 /*@ 3592 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3593 3594 Not Collective 3595 3596 Input Parameters: 3597 + dm - The `DMPLEX` 3598 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3599 . supportPos - The local index in the cone where the point should be put 3600 - supportPoint - The mesh point to insert 3601 3602 Level: beginner 3603 3604 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3605 @*/ 3606 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3607 { 3608 DM_Plex *mesh = (DM_Plex *)dm->data; 3609 PetscInt pStart, pEnd; 3610 PetscInt dof, off; 3611 3612 PetscFunctionBegin; 3613 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3614 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3615 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3616 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3617 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); 3618 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); 3619 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); 3620 mesh->supports[off + supportPos] = supportPoint; 3621 PetscFunctionReturn(PETSC_SUCCESS); 3622 } 3623 3624 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3625 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3626 { 3627 switch (ct) { 3628 case DM_POLYTOPE_SEGMENT: 3629 if (o == -1) return -2; 3630 break; 3631 case DM_POLYTOPE_TRIANGLE: 3632 if (o == -3) return -1; 3633 if (o == -2) return -3; 3634 if (o == -1) return -2; 3635 break; 3636 case DM_POLYTOPE_QUADRILATERAL: 3637 if (o == -4) return -2; 3638 if (o == -3) return -1; 3639 if (o == -2) return -4; 3640 if (o == -1) return -3; 3641 break; 3642 default: 3643 return o; 3644 } 3645 return o; 3646 } 3647 3648 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3649 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3650 { 3651 switch (ct) { 3652 case DM_POLYTOPE_SEGMENT: 3653 if ((o == -2) || (o == 1)) return -1; 3654 if (o == -1) return 0; 3655 break; 3656 case DM_POLYTOPE_TRIANGLE: 3657 if (o == -3) return -2; 3658 if (o == -2) return -1; 3659 if (o == -1) return -3; 3660 break; 3661 case DM_POLYTOPE_QUADRILATERAL: 3662 if (o == -4) return -2; 3663 if (o == -3) return -1; 3664 if (o == -2) return -4; 3665 if (o == -1) return -3; 3666 break; 3667 default: 3668 return o; 3669 } 3670 return o; 3671 } 3672 3673 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3674 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3675 { 3676 PetscInt pStart, pEnd, p; 3677 3678 PetscFunctionBegin; 3679 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3680 for (p = pStart; p < pEnd; ++p) { 3681 const PetscInt *cone, *ornt; 3682 PetscInt coneSize, c; 3683 3684 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3685 PetscCall(DMPlexGetCone(dm, p, &cone)); 3686 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3687 for (c = 0; c < coneSize; ++c) { 3688 DMPolytopeType ct; 3689 const PetscInt o = ornt[c]; 3690 3691 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3692 switch (ct) { 3693 case DM_POLYTOPE_SEGMENT: 3694 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3695 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3696 break; 3697 case DM_POLYTOPE_TRIANGLE: 3698 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3699 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3700 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3701 break; 3702 case DM_POLYTOPE_QUADRILATERAL: 3703 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3704 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3705 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3706 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3707 break; 3708 default: 3709 break; 3710 } 3711 } 3712 } 3713 PetscFunctionReturn(PETSC_SUCCESS); 3714 } 3715 3716 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3717 { 3718 DM_Plex *mesh = (DM_Plex *)dm->data; 3719 3720 PetscFunctionBeginHot; 3721 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3722 if (useCone) { 3723 PetscCall(DMPlexGetConeSize(dm, p, size)); 3724 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3725 } else { 3726 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3727 PetscCall(DMPlexGetSupport(dm, p, arr)); 3728 } 3729 } else { 3730 if (useCone) { 3731 const PetscSection s = mesh->coneSection; 3732 const PetscInt ps = p - s->pStart; 3733 const PetscInt off = s->atlasOff[ps]; 3734 3735 *size = s->atlasDof[ps]; 3736 *arr = mesh->cones + off; 3737 *ornt = mesh->coneOrientations + off; 3738 } else { 3739 const PetscSection s = mesh->supportSection; 3740 const PetscInt ps = p - s->pStart; 3741 const PetscInt off = s->atlasOff[ps]; 3742 3743 *size = s->atlasDof[ps]; 3744 *arr = mesh->supports + off; 3745 } 3746 } 3747 PetscFunctionReturn(PETSC_SUCCESS); 3748 } 3749 3750 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3751 { 3752 DM_Plex *mesh = (DM_Plex *)dm->data; 3753 3754 PetscFunctionBeginHot; 3755 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3756 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3757 } 3758 PetscFunctionReturn(PETSC_SUCCESS); 3759 } 3760 3761 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3762 { 3763 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3764 PetscInt *closure; 3765 const PetscInt *tmp = NULL, *tmpO = NULL; 3766 PetscInt off = 0, tmpSize, t; 3767 3768 PetscFunctionBeginHot; 3769 if (ornt) { 3770 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3771 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3772 } 3773 if (*points) { 3774 closure = *points; 3775 } else { 3776 PetscInt maxConeSize, maxSupportSize; 3777 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3778 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3779 } 3780 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3781 if (ct == DM_POLYTOPE_UNKNOWN) { 3782 closure[off++] = p; 3783 closure[off++] = 0; 3784 for (t = 0; t < tmpSize; ++t) { 3785 closure[off++] = tmp[t]; 3786 closure[off++] = tmpO ? tmpO[t] : 0; 3787 } 3788 } else { 3789 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3790 3791 /* We assume that cells with a valid type have faces with a valid type */ 3792 closure[off++] = p; 3793 closure[off++] = ornt; 3794 for (t = 0; t < tmpSize; ++t) { 3795 DMPolytopeType ft; 3796 3797 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3798 closure[off++] = tmp[arr[t]]; 3799 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3800 } 3801 } 3802 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3803 if (numPoints) *numPoints = tmpSize + 1; 3804 if (points) *points = closure; 3805 PetscFunctionReturn(PETSC_SUCCESS); 3806 } 3807 3808 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3809 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3810 { 3811 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3812 const PetscInt *cone, *ornt; 3813 PetscInt *pts, *closure = NULL; 3814 DMPolytopeType ft; 3815 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3816 PetscInt dim, coneSize, c, d, clSize, cl; 3817 3818 PetscFunctionBeginHot; 3819 PetscCall(DMGetDimension(dm, &dim)); 3820 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3821 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3822 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3823 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3824 maxSize = PetscMax(coneSeries, supportSeries); 3825 if (*points) { 3826 pts = *points; 3827 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3828 c = 0; 3829 pts[c++] = point; 3830 pts[c++] = o; 3831 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3832 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3833 for (cl = 0; cl < clSize * 2; cl += 2) { 3834 pts[c++] = closure[cl]; 3835 pts[c++] = closure[cl + 1]; 3836 } 3837 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3838 for (cl = 0; cl < clSize * 2; cl += 2) { 3839 pts[c++] = closure[cl]; 3840 pts[c++] = closure[cl + 1]; 3841 } 3842 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3843 for (d = 2; d < coneSize; ++d) { 3844 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3845 pts[c++] = cone[arr[d * 2 + 0]]; 3846 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3847 } 3848 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3849 if (dim >= 3) { 3850 for (d = 2; d < coneSize; ++d) { 3851 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3852 const PetscInt *fcone, *fornt; 3853 PetscInt fconeSize, fc, i; 3854 3855 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3856 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3857 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3858 for (fc = 0; fc < fconeSize; ++fc) { 3859 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3860 const PetscInt co = farr[fc * 2 + 1]; 3861 3862 for (i = 0; i < c; i += 2) 3863 if (pts[i] == cp) break; 3864 if (i == c) { 3865 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3866 pts[c++] = cp; 3867 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3868 } 3869 } 3870 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3871 } 3872 } 3873 *numPoints = c / 2; 3874 *points = pts; 3875 PetscFunctionReturn(PETSC_SUCCESS); 3876 } 3877 3878 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3879 { 3880 DMPolytopeType ct; 3881 PetscInt *closure, *fifo; 3882 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3883 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3884 PetscInt depth, maxSize; 3885 3886 PetscFunctionBeginHot; 3887 PetscCall(DMPlexGetDepth(dm, &depth)); 3888 if (depth == 1) { 3889 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3890 PetscFunctionReturn(PETSC_SUCCESS); 3891 } 3892 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3893 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3894 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3895 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3896 PetscFunctionReturn(PETSC_SUCCESS); 3897 } 3898 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3899 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3900 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3901 maxSize = PetscMax(coneSeries, supportSeries); 3902 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3903 if (*points) { 3904 closure = *points; 3905 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3906 closure[closureSize++] = p; 3907 closure[closureSize++] = ornt; 3908 fifo[fifoSize++] = p; 3909 fifo[fifoSize++] = ornt; 3910 fifo[fifoSize++] = ct; 3911 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3912 while (fifoSize - fifoStart) { 3913 const PetscInt q = fifo[fifoStart++]; 3914 const PetscInt o = fifo[fifoStart++]; 3915 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3916 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3917 const PetscInt *tmp, *tmpO = NULL; 3918 PetscInt tmpSize, t; 3919 3920 if (PetscDefined(USE_DEBUG)) { 3921 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3922 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); 3923 } 3924 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3925 for (t = 0; t < tmpSize; ++t) { 3926 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3927 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3928 const PetscInt cp = tmp[ip]; 3929 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3930 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3931 PetscInt c; 3932 3933 /* Check for duplicate */ 3934 for (c = 0; c < closureSize; c += 2) { 3935 if (closure[c] == cp) break; 3936 } 3937 if (c == closureSize) { 3938 closure[closureSize++] = cp; 3939 closure[closureSize++] = co; 3940 fifo[fifoSize++] = cp; 3941 fifo[fifoSize++] = co; 3942 fifo[fifoSize++] = ct; 3943 } 3944 } 3945 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3946 } 3947 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3948 if (numPoints) *numPoints = closureSize / 2; 3949 if (points) *points = closure; 3950 PetscFunctionReturn(PETSC_SUCCESS); 3951 } 3952 3953 /*@C 3954 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3955 3956 Not Collective 3957 3958 Input Parameters: 3959 + dm - The `DMPLEX` 3960 . p - The mesh point 3961 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 3962 3963 Input/Output Parameter: 3964 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3965 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 3966 3967 Output Parameter: 3968 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 3969 3970 Level: beginner 3971 3972 Note: 3973 If using internal storage (points is `NULL` on input), each call overwrites the last output. 3974 3975 Fortran Notes: 3976 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 3977 3978 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3979 @*/ 3980 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3981 { 3982 PetscFunctionBeginHot; 3983 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3984 if (numPoints) PetscAssertPointer(numPoints, 4); 3985 if (points) PetscAssertPointer(points, 5); 3986 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3987 PetscFunctionReturn(PETSC_SUCCESS); 3988 } 3989 3990 /*@C 3991 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3992 3993 Not Collective 3994 3995 Input Parameters: 3996 + dm - The `DMPLEX` 3997 . p - The mesh point 3998 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 3999 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4000 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4001 4002 Level: beginner 4003 4004 Note: 4005 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4006 4007 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4008 @*/ 4009 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4010 { 4011 PetscFunctionBeginHot; 4012 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4013 if (numPoints) *numPoints = 0; 4014 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4015 PetscFunctionReturn(PETSC_SUCCESS); 4016 } 4017 4018 /*@ 4019 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4020 4021 Not Collective 4022 4023 Input Parameter: 4024 . dm - The `DMPLEX` 4025 4026 Output Parameters: 4027 + maxConeSize - The maximum number of in-edges 4028 - maxSupportSize - The maximum number of out-edges 4029 4030 Level: beginner 4031 4032 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4033 @*/ 4034 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4035 { 4036 DM_Plex *mesh = (DM_Plex *)dm->data; 4037 4038 PetscFunctionBegin; 4039 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4040 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4041 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4042 PetscFunctionReturn(PETSC_SUCCESS); 4043 } 4044 4045 PetscErrorCode DMSetUp_Plex(DM dm) 4046 { 4047 DM_Plex *mesh = (DM_Plex *)dm->data; 4048 PetscInt size, maxSupportSize; 4049 4050 PetscFunctionBegin; 4051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4052 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4053 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4054 PetscCall(PetscMalloc1(size, &mesh->cones)); 4055 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4056 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4057 if (maxSupportSize) { 4058 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4059 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4060 PetscCall(PetscMalloc1(size, &mesh->supports)); 4061 } 4062 PetscFunctionReturn(PETSC_SUCCESS); 4063 } 4064 4065 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4066 { 4067 PetscFunctionBegin; 4068 if (subdm) PetscCall(DMClone(dm, subdm)); 4069 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 4070 if (subdm) (*subdm)->useNatural = dm->useNatural; 4071 if (dm->useNatural && dm->sfMigration) { 4072 PetscSF sfNatural; 4073 4074 (*subdm)->sfMigration = dm->sfMigration; 4075 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4076 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4077 (*subdm)->sfNatural = sfNatural; 4078 } 4079 PetscFunctionReturn(PETSC_SUCCESS); 4080 } 4081 4082 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4083 { 4084 PetscInt i = 0; 4085 4086 PetscFunctionBegin; 4087 PetscCall(DMClone(dms[0], superdm)); 4088 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4089 (*superdm)->useNatural = PETSC_FALSE; 4090 for (i = 0; i < len; i++) { 4091 if (dms[i]->useNatural && dms[i]->sfMigration) { 4092 PetscSF sfNatural; 4093 4094 (*superdm)->sfMigration = dms[i]->sfMigration; 4095 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4096 (*superdm)->useNatural = PETSC_TRUE; 4097 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4098 (*superdm)->sfNatural = sfNatural; 4099 break; 4100 } 4101 } 4102 PetscFunctionReturn(PETSC_SUCCESS); 4103 } 4104 4105 /*@ 4106 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4107 4108 Not Collective 4109 4110 Input Parameter: 4111 . dm - The `DMPLEX` 4112 4113 Level: beginner 4114 4115 Note: 4116 This should be called after all calls to `DMPlexSetCone()` 4117 4118 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4119 @*/ 4120 PetscErrorCode DMPlexSymmetrize(DM dm) 4121 { 4122 DM_Plex *mesh = (DM_Plex *)dm->data; 4123 PetscInt *offsets; 4124 PetscInt supportSize; 4125 PetscInt pStart, pEnd, p; 4126 4127 PetscFunctionBegin; 4128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4129 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4130 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4131 /* Calculate support sizes */ 4132 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4133 for (p = pStart; p < pEnd; ++p) { 4134 PetscInt dof, off, c; 4135 4136 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4137 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4138 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4139 } 4140 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4141 /* Calculate supports */ 4142 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4143 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4144 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4145 for (p = pStart; p < pEnd; ++p) { 4146 PetscInt dof, off, c; 4147 4148 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4149 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4150 for (c = off; c < off + dof; ++c) { 4151 const PetscInt q = mesh->cones[c]; 4152 PetscInt offS; 4153 4154 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4155 4156 mesh->supports[offS + offsets[q]] = p; 4157 ++offsets[q]; 4158 } 4159 } 4160 PetscCall(PetscFree(offsets)); 4161 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4162 PetscFunctionReturn(PETSC_SUCCESS); 4163 } 4164 4165 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4166 { 4167 IS stratumIS; 4168 4169 PetscFunctionBegin; 4170 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4171 if (PetscDefined(USE_DEBUG)) { 4172 PetscInt qStart, qEnd, numLevels, level; 4173 PetscBool overlap = PETSC_FALSE; 4174 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4175 for (level = 0; level < numLevels; level++) { 4176 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4177 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4178 overlap = PETSC_TRUE; 4179 break; 4180 } 4181 } 4182 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); 4183 } 4184 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4185 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4186 PetscCall(ISDestroy(&stratumIS)); 4187 PetscFunctionReturn(PETSC_SUCCESS); 4188 } 4189 4190 /*@ 4191 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4192 4193 Collective 4194 4195 Input Parameter: 4196 . dm - The `DMPLEX` 4197 4198 Level: beginner 4199 4200 Notes: 4201 The strata group all points of the same grade, and this function calculates the strata. This 4202 grade can be seen as the height (or depth) of the point in the DAG. 4203 4204 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4205 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4206 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4207 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4208 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4209 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4210 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4211 4212 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4213 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4214 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 4215 to interpolate only that one (e0), so that 4216 .vb 4217 cone(c0) = {e0, v2} 4218 cone(e0) = {v0, v1} 4219 .ve 4220 If `DMPlexStratify()` is run on this mesh, it will give depths 4221 .vb 4222 depth 0 = {v0, v1, v2} 4223 depth 1 = {e0, c0} 4224 .ve 4225 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4226 4227 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4228 4229 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4230 @*/ 4231 PetscErrorCode DMPlexStratify(DM dm) 4232 { 4233 DM_Plex *mesh = (DM_Plex *)dm->data; 4234 DMLabel label; 4235 PetscInt pStart, pEnd, p; 4236 PetscInt numRoots = 0, numLeaves = 0; 4237 4238 PetscFunctionBegin; 4239 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4240 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4241 4242 /* Create depth label */ 4243 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4244 PetscCall(DMCreateLabel(dm, "depth")); 4245 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4246 4247 { 4248 /* Initialize roots and count leaves */ 4249 PetscInt sMin = PETSC_MAX_INT; 4250 PetscInt sMax = PETSC_MIN_INT; 4251 PetscInt coneSize, supportSize; 4252 4253 for (p = pStart; p < pEnd; ++p) { 4254 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4255 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4256 if (!coneSize && supportSize) { 4257 sMin = PetscMin(p, sMin); 4258 sMax = PetscMax(p, sMax); 4259 ++numRoots; 4260 } else if (!supportSize && coneSize) { 4261 ++numLeaves; 4262 } else if (!supportSize && !coneSize) { 4263 /* Isolated points */ 4264 sMin = PetscMin(p, sMin); 4265 sMax = PetscMax(p, sMax); 4266 } 4267 } 4268 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4269 } 4270 4271 if (numRoots + numLeaves == (pEnd - pStart)) { 4272 PetscInt sMin = PETSC_MAX_INT; 4273 PetscInt sMax = PETSC_MIN_INT; 4274 PetscInt coneSize, supportSize; 4275 4276 for (p = pStart; p < pEnd; ++p) { 4277 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4278 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4279 if (!supportSize && coneSize) { 4280 sMin = PetscMin(p, sMin); 4281 sMax = PetscMax(p, sMax); 4282 } 4283 } 4284 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4285 } else { 4286 PetscInt level = 0; 4287 PetscInt qStart, qEnd, q; 4288 4289 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4290 while (qEnd > qStart) { 4291 PetscInt sMin = PETSC_MAX_INT; 4292 PetscInt sMax = PETSC_MIN_INT; 4293 4294 for (q = qStart; q < qEnd; ++q) { 4295 const PetscInt *support; 4296 PetscInt supportSize, s; 4297 4298 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4299 PetscCall(DMPlexGetSupport(dm, q, &support)); 4300 for (s = 0; s < supportSize; ++s) { 4301 sMin = PetscMin(support[s], sMin); 4302 sMax = PetscMax(support[s], sMax); 4303 } 4304 } 4305 PetscCall(DMLabelGetNumValues(label, &level)); 4306 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4307 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4308 } 4309 } 4310 { /* just in case there is an empty process */ 4311 PetscInt numValues, maxValues = 0, v; 4312 4313 PetscCall(DMLabelGetNumValues(label, &numValues)); 4314 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4315 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4316 } 4317 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4318 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4319 PetscFunctionReturn(PETSC_SUCCESS); 4320 } 4321 4322 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4323 { 4324 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4325 PetscInt dim, depth, pheight, coneSize; 4326 4327 PetscFunctionBeginHot; 4328 PetscCall(DMGetDimension(dm, &dim)); 4329 PetscCall(DMPlexGetDepth(dm, &depth)); 4330 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4331 pheight = depth - pdepth; 4332 if (depth <= 1) { 4333 switch (pdepth) { 4334 case 0: 4335 ct = DM_POLYTOPE_POINT; 4336 break; 4337 case 1: 4338 switch (coneSize) { 4339 case 2: 4340 ct = DM_POLYTOPE_SEGMENT; 4341 break; 4342 case 3: 4343 ct = DM_POLYTOPE_TRIANGLE; 4344 break; 4345 case 4: 4346 switch (dim) { 4347 case 2: 4348 ct = DM_POLYTOPE_QUADRILATERAL; 4349 break; 4350 case 3: 4351 ct = DM_POLYTOPE_TETRAHEDRON; 4352 break; 4353 default: 4354 break; 4355 } 4356 break; 4357 case 5: 4358 ct = DM_POLYTOPE_PYRAMID; 4359 break; 4360 case 6: 4361 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4362 break; 4363 case 8: 4364 ct = DM_POLYTOPE_HEXAHEDRON; 4365 break; 4366 default: 4367 break; 4368 } 4369 } 4370 } else { 4371 if (pdepth == 0) { 4372 ct = DM_POLYTOPE_POINT; 4373 } else if (pheight == 0) { 4374 switch (dim) { 4375 case 1: 4376 switch (coneSize) { 4377 case 2: 4378 ct = DM_POLYTOPE_SEGMENT; 4379 break; 4380 default: 4381 break; 4382 } 4383 break; 4384 case 2: 4385 switch (coneSize) { 4386 case 3: 4387 ct = DM_POLYTOPE_TRIANGLE; 4388 break; 4389 case 4: 4390 ct = DM_POLYTOPE_QUADRILATERAL; 4391 break; 4392 default: 4393 break; 4394 } 4395 break; 4396 case 3: 4397 switch (coneSize) { 4398 case 4: 4399 ct = DM_POLYTOPE_TETRAHEDRON; 4400 break; 4401 case 5: { 4402 const PetscInt *cone; 4403 PetscInt faceConeSize; 4404 4405 PetscCall(DMPlexGetCone(dm, p, &cone)); 4406 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4407 switch (faceConeSize) { 4408 case 3: 4409 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4410 break; 4411 case 4: 4412 ct = DM_POLYTOPE_PYRAMID; 4413 break; 4414 } 4415 } break; 4416 case 6: 4417 ct = DM_POLYTOPE_HEXAHEDRON; 4418 break; 4419 default: 4420 break; 4421 } 4422 break; 4423 default: 4424 break; 4425 } 4426 } else if (pheight > 0) { 4427 switch (coneSize) { 4428 case 2: 4429 ct = DM_POLYTOPE_SEGMENT; 4430 break; 4431 case 3: 4432 ct = DM_POLYTOPE_TRIANGLE; 4433 break; 4434 case 4: 4435 ct = DM_POLYTOPE_QUADRILATERAL; 4436 break; 4437 default: 4438 break; 4439 } 4440 } 4441 } 4442 *pt = ct; 4443 PetscFunctionReturn(PETSC_SUCCESS); 4444 } 4445 4446 /*@ 4447 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4448 4449 Collective 4450 4451 Input Parameter: 4452 . dm - The `DMPLEX` 4453 4454 Level: developer 4455 4456 Note: 4457 This function is normally called automatically when a cell type is requested. It creates an 4458 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4459 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4460 4461 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4462 4463 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4464 @*/ 4465 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4466 { 4467 DM_Plex *mesh; 4468 DMLabel ctLabel; 4469 PetscInt pStart, pEnd, p; 4470 4471 PetscFunctionBegin; 4472 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4473 mesh = (DM_Plex *)dm->data; 4474 PetscCall(DMCreateLabel(dm, "celltype")); 4475 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4476 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4477 PetscCall(PetscFree(mesh->cellTypes)); 4478 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4479 for (p = pStart; p < pEnd; ++p) { 4480 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4481 PetscInt pdepth; 4482 4483 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4484 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4485 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4486 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4487 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4488 } 4489 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4490 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4491 PetscFunctionReturn(PETSC_SUCCESS); 4492 } 4493 4494 /*@C 4495 DMPlexGetJoin - Get an array for the join of the set of points 4496 4497 Not Collective 4498 4499 Input Parameters: 4500 + dm - The `DMPLEX` object 4501 . numPoints - The number of input points for the join 4502 - points - The input points 4503 4504 Output Parameters: 4505 + numCoveredPoints - The number of points in the join 4506 - coveredPoints - The points in the join 4507 4508 Level: intermediate 4509 4510 Note: 4511 Currently, this is restricted to a single level join 4512 4513 Fortran Notes: 4514 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4515 4516 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4517 @*/ 4518 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4519 { 4520 DM_Plex *mesh = (DM_Plex *)dm->data; 4521 PetscInt *join[2]; 4522 PetscInt joinSize, i = 0; 4523 PetscInt dof, off, p, c, m; 4524 PetscInt maxSupportSize; 4525 4526 PetscFunctionBegin; 4527 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4528 PetscAssertPointer(points, 3); 4529 PetscAssertPointer(numCoveredPoints, 4); 4530 PetscAssertPointer(coveredPoints, 5); 4531 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4532 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4533 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4534 /* Copy in support of first point */ 4535 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4536 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4537 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4538 /* Check each successive support */ 4539 for (p = 1; p < numPoints; ++p) { 4540 PetscInt newJoinSize = 0; 4541 4542 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4543 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4544 for (c = 0; c < dof; ++c) { 4545 const PetscInt point = mesh->supports[off + c]; 4546 4547 for (m = 0; m < joinSize; ++m) { 4548 if (point == join[i][m]) { 4549 join[1 - i][newJoinSize++] = point; 4550 break; 4551 } 4552 } 4553 } 4554 joinSize = newJoinSize; 4555 i = 1 - i; 4556 } 4557 *numCoveredPoints = joinSize; 4558 *coveredPoints = join[i]; 4559 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4560 PetscFunctionReturn(PETSC_SUCCESS); 4561 } 4562 4563 /*@C 4564 DMPlexRestoreJoin - Restore an array for the join of the set of points 4565 4566 Not Collective 4567 4568 Input Parameters: 4569 + dm - The `DMPLEX` object 4570 . numPoints - The number of input points for the join 4571 - points - The input points 4572 4573 Output Parameters: 4574 + numCoveredPoints - The number of points in the join 4575 - coveredPoints - The points in the join 4576 4577 Level: intermediate 4578 4579 Fortran Notes: 4580 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4581 4582 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4583 @*/ 4584 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4585 { 4586 PetscFunctionBegin; 4587 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4588 if (points) PetscAssertPointer(points, 3); 4589 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4590 PetscAssertPointer(coveredPoints, 5); 4591 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4592 if (numCoveredPoints) *numCoveredPoints = 0; 4593 PetscFunctionReturn(PETSC_SUCCESS); 4594 } 4595 4596 /*@C 4597 DMPlexGetFullJoin - Get an array for the join of the set of points 4598 4599 Not Collective 4600 4601 Input Parameters: 4602 + dm - The `DMPLEX` object 4603 . numPoints - The number of input points for the join 4604 - points - The input points 4605 4606 Output Parameters: 4607 + numCoveredPoints - The number of points in the join 4608 - coveredPoints - The points in the join 4609 4610 Level: intermediate 4611 4612 Fortran Notes: 4613 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4614 4615 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4616 @*/ 4617 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4618 { 4619 PetscInt *offsets, **closures; 4620 PetscInt *join[2]; 4621 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4622 PetscInt p, d, c, m, ms; 4623 4624 PetscFunctionBegin; 4625 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4626 PetscAssertPointer(points, 3); 4627 PetscAssertPointer(numCoveredPoints, 4); 4628 PetscAssertPointer(coveredPoints, 5); 4629 4630 PetscCall(DMPlexGetDepth(dm, &depth)); 4631 PetscCall(PetscCalloc1(numPoints, &closures)); 4632 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4633 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4634 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4635 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4636 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4637 4638 for (p = 0; p < numPoints; ++p) { 4639 PetscInt closureSize; 4640 4641 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4642 4643 offsets[p * (depth + 2) + 0] = 0; 4644 for (d = 0; d < depth + 1; ++d) { 4645 PetscInt pStart, pEnd, i; 4646 4647 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4648 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4649 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4650 offsets[p * (depth + 2) + d + 1] = i; 4651 break; 4652 } 4653 } 4654 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4655 } 4656 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); 4657 } 4658 for (d = 0; d < depth + 1; ++d) { 4659 PetscInt dof; 4660 4661 /* Copy in support of first point */ 4662 dof = offsets[d + 1] - offsets[d]; 4663 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4664 /* Check each successive cone */ 4665 for (p = 1; p < numPoints && joinSize; ++p) { 4666 PetscInt newJoinSize = 0; 4667 4668 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4669 for (c = 0; c < dof; ++c) { 4670 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4671 4672 for (m = 0; m < joinSize; ++m) { 4673 if (point == join[i][m]) { 4674 join[1 - i][newJoinSize++] = point; 4675 break; 4676 } 4677 } 4678 } 4679 joinSize = newJoinSize; 4680 i = 1 - i; 4681 } 4682 if (joinSize) break; 4683 } 4684 *numCoveredPoints = joinSize; 4685 *coveredPoints = join[i]; 4686 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4687 PetscCall(PetscFree(closures)); 4688 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4689 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4690 PetscFunctionReturn(PETSC_SUCCESS); 4691 } 4692 4693 /*@C 4694 DMPlexGetMeet - Get an array for the meet of the set of points 4695 4696 Not Collective 4697 4698 Input Parameters: 4699 + dm - The `DMPLEX` object 4700 . numPoints - The number of input points for the meet 4701 - points - The input points 4702 4703 Output Parameters: 4704 + numCoveringPoints - The number of points in the meet 4705 - coveringPoints - The points in the meet 4706 4707 Level: intermediate 4708 4709 Note: 4710 Currently, this is restricted to a single level meet 4711 4712 Fortran Notes: 4713 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4714 4715 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4716 @*/ 4717 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4718 { 4719 DM_Plex *mesh = (DM_Plex *)dm->data; 4720 PetscInt *meet[2]; 4721 PetscInt meetSize, i = 0; 4722 PetscInt dof, off, p, c, m; 4723 PetscInt maxConeSize; 4724 4725 PetscFunctionBegin; 4726 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4727 PetscAssertPointer(points, 3); 4728 PetscAssertPointer(numCoveringPoints, 4); 4729 PetscAssertPointer(coveringPoints, 5); 4730 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4731 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4732 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4733 /* Copy in cone of first point */ 4734 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4735 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4736 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4737 /* Check each successive cone */ 4738 for (p = 1; p < numPoints; ++p) { 4739 PetscInt newMeetSize = 0; 4740 4741 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4742 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4743 for (c = 0; c < dof; ++c) { 4744 const PetscInt point = mesh->cones[off + c]; 4745 4746 for (m = 0; m < meetSize; ++m) { 4747 if (point == meet[i][m]) { 4748 meet[1 - i][newMeetSize++] = point; 4749 break; 4750 } 4751 } 4752 } 4753 meetSize = newMeetSize; 4754 i = 1 - i; 4755 } 4756 *numCoveringPoints = meetSize; 4757 *coveringPoints = meet[i]; 4758 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4759 PetscFunctionReturn(PETSC_SUCCESS); 4760 } 4761 4762 /*@C 4763 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4764 4765 Not Collective 4766 4767 Input Parameters: 4768 + dm - The `DMPLEX` object 4769 . numPoints - The number of input points for the meet 4770 - points - The input points 4771 4772 Output Parameters: 4773 + numCoveredPoints - The number of points in the meet 4774 - coveredPoints - The points in the meet 4775 4776 Level: intermediate 4777 4778 Fortran Notes: 4779 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4780 4781 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4782 @*/ 4783 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4784 { 4785 PetscFunctionBegin; 4786 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4787 if (points) PetscAssertPointer(points, 3); 4788 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4789 PetscAssertPointer(coveredPoints, 5); 4790 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4791 if (numCoveredPoints) *numCoveredPoints = 0; 4792 PetscFunctionReturn(PETSC_SUCCESS); 4793 } 4794 4795 /*@C 4796 DMPlexGetFullMeet - Get an array for the meet of the set of points 4797 4798 Not Collective 4799 4800 Input Parameters: 4801 + dm - The `DMPLEX` object 4802 . numPoints - The number of input points for the meet 4803 - points - The input points 4804 4805 Output Parameters: 4806 + numCoveredPoints - The number of points in the meet 4807 - coveredPoints - The points in the meet 4808 4809 Level: intermediate 4810 4811 Fortran Notes: 4812 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4813 4814 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4815 @*/ 4816 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4817 { 4818 PetscInt *offsets, **closures; 4819 PetscInt *meet[2]; 4820 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4821 PetscInt p, h, c, m, mc; 4822 4823 PetscFunctionBegin; 4824 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4825 PetscAssertPointer(points, 3); 4826 PetscAssertPointer(numCoveredPoints, 4); 4827 PetscAssertPointer(coveredPoints, 5); 4828 4829 PetscCall(DMPlexGetDepth(dm, &height)); 4830 PetscCall(PetscMalloc1(numPoints, &closures)); 4831 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4832 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4833 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4834 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4835 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4836 4837 for (p = 0; p < numPoints; ++p) { 4838 PetscInt closureSize; 4839 4840 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4841 4842 offsets[p * (height + 2) + 0] = 0; 4843 for (h = 0; h < height + 1; ++h) { 4844 PetscInt pStart, pEnd, i; 4845 4846 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4847 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4848 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4849 offsets[p * (height + 2) + h + 1] = i; 4850 break; 4851 } 4852 } 4853 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4854 } 4855 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); 4856 } 4857 for (h = 0; h < height + 1; ++h) { 4858 PetscInt dof; 4859 4860 /* Copy in cone of first point */ 4861 dof = offsets[h + 1] - offsets[h]; 4862 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4863 /* Check each successive cone */ 4864 for (p = 1; p < numPoints && meetSize; ++p) { 4865 PetscInt newMeetSize = 0; 4866 4867 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4868 for (c = 0; c < dof; ++c) { 4869 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4870 4871 for (m = 0; m < meetSize; ++m) { 4872 if (point == meet[i][m]) { 4873 meet[1 - i][newMeetSize++] = point; 4874 break; 4875 } 4876 } 4877 } 4878 meetSize = newMeetSize; 4879 i = 1 - i; 4880 } 4881 if (meetSize) break; 4882 } 4883 *numCoveredPoints = meetSize; 4884 *coveredPoints = meet[i]; 4885 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4886 PetscCall(PetscFree(closures)); 4887 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4888 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4889 PetscFunctionReturn(PETSC_SUCCESS); 4890 } 4891 4892 /*@C 4893 DMPlexEqual - Determine if two `DM` have the same topology 4894 4895 Not Collective 4896 4897 Input Parameters: 4898 + dmA - A `DMPLEX` object 4899 - dmB - A `DMPLEX` object 4900 4901 Output Parameter: 4902 . equal - `PETSC_TRUE` if the topologies are identical 4903 4904 Level: intermediate 4905 4906 Note: 4907 We are not solving graph isomorphism, so we do not permute. 4908 4909 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4910 @*/ 4911 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4912 { 4913 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4914 4915 PetscFunctionBegin; 4916 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4917 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4918 PetscAssertPointer(equal, 3); 4919 4920 *equal = PETSC_FALSE; 4921 PetscCall(DMPlexGetDepth(dmA, &depth)); 4922 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4923 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 4924 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4925 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4926 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 4927 for (p = pStart; p < pEnd; ++p) { 4928 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4929 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4930 4931 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4932 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4933 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4934 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4935 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4936 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4937 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4938 for (c = 0; c < coneSize; ++c) { 4939 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4940 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4941 } 4942 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4943 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4944 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4945 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4946 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4947 for (s = 0; s < supportSize; ++s) { 4948 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 4949 } 4950 } 4951 *equal = PETSC_TRUE; 4952 PetscFunctionReturn(PETSC_SUCCESS); 4953 } 4954 4955 /*@C 4956 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4957 4958 Not Collective 4959 4960 Input Parameters: 4961 + dm - The `DMPLEX` 4962 . cellDim - The cell dimension 4963 - numCorners - The number of vertices on a cell 4964 4965 Output Parameter: 4966 . numFaceVertices - The number of vertices on a face 4967 4968 Level: developer 4969 4970 Note: 4971 Of course this can only work for a restricted set of symmetric shapes 4972 4973 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4974 @*/ 4975 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4976 { 4977 MPI_Comm comm; 4978 4979 PetscFunctionBegin; 4980 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4981 PetscAssertPointer(numFaceVertices, 4); 4982 switch (cellDim) { 4983 case 0: 4984 *numFaceVertices = 0; 4985 break; 4986 case 1: 4987 *numFaceVertices = 1; 4988 break; 4989 case 2: 4990 switch (numCorners) { 4991 case 3: /* triangle */ 4992 *numFaceVertices = 2; /* Edge has 2 vertices */ 4993 break; 4994 case 4: /* quadrilateral */ 4995 *numFaceVertices = 2; /* Edge has 2 vertices */ 4996 break; 4997 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4998 *numFaceVertices = 3; /* Edge has 3 vertices */ 4999 break; 5000 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5001 *numFaceVertices = 3; /* Edge has 3 vertices */ 5002 break; 5003 default: 5004 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5005 } 5006 break; 5007 case 3: 5008 switch (numCorners) { 5009 case 4: /* tetradehdron */ 5010 *numFaceVertices = 3; /* Face has 3 vertices */ 5011 break; 5012 case 6: /* tet cohesive cells */ 5013 *numFaceVertices = 4; /* Face has 4 vertices */ 5014 break; 5015 case 8: /* hexahedron */ 5016 *numFaceVertices = 4; /* Face has 4 vertices */ 5017 break; 5018 case 9: /* tet cohesive Lagrange cells */ 5019 *numFaceVertices = 6; /* Face has 6 vertices */ 5020 break; 5021 case 10: /* quadratic tetrahedron */ 5022 *numFaceVertices = 6; /* Face has 6 vertices */ 5023 break; 5024 case 12: /* hex cohesive Lagrange cells */ 5025 *numFaceVertices = 6; /* Face has 6 vertices */ 5026 break; 5027 case 18: /* quadratic tet cohesive Lagrange cells */ 5028 *numFaceVertices = 6; /* Face has 6 vertices */ 5029 break; 5030 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5031 *numFaceVertices = 9; /* Face has 9 vertices */ 5032 break; 5033 default: 5034 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5035 } 5036 break; 5037 default: 5038 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5039 } 5040 PetscFunctionReturn(PETSC_SUCCESS); 5041 } 5042 5043 /*@ 5044 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5045 5046 Not Collective 5047 5048 Input Parameter: 5049 . dm - The `DMPLEX` object 5050 5051 Output Parameter: 5052 . depthLabel - The `DMLabel` recording point depth 5053 5054 Level: developer 5055 5056 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5057 @*/ 5058 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5059 { 5060 PetscFunctionBegin; 5061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5062 PetscAssertPointer(depthLabel, 2); 5063 *depthLabel = dm->depthLabel; 5064 PetscFunctionReturn(PETSC_SUCCESS); 5065 } 5066 5067 /*@ 5068 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5069 5070 Not Collective 5071 5072 Input Parameter: 5073 . dm - The `DMPLEX` object 5074 5075 Output Parameter: 5076 . depth - The number of strata (breadth first levels) in the DAG 5077 5078 Level: developer 5079 5080 Notes: 5081 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5082 5083 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5084 5085 An empty mesh gives -1. 5086 5087 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5088 @*/ 5089 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5090 { 5091 DM_Plex *mesh = (DM_Plex *)dm->data; 5092 DMLabel label; 5093 PetscInt d = 0; 5094 5095 PetscFunctionBegin; 5096 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5097 PetscAssertPointer(depth, 2); 5098 if (mesh->tr) { 5099 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5100 } else { 5101 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5102 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5103 *depth = d - 1; 5104 } 5105 PetscFunctionReturn(PETSC_SUCCESS); 5106 } 5107 5108 /*@ 5109 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5110 5111 Not Collective 5112 5113 Input Parameters: 5114 + dm - The `DMPLEX` object 5115 - depth - The requested depth 5116 5117 Output Parameters: 5118 + start - The first point at this `depth` 5119 - end - One beyond the last point at this `depth` 5120 5121 Level: developer 5122 5123 Notes: 5124 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5125 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5126 higher dimension, e.g., "edges". 5127 5128 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5129 @*/ 5130 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5131 { 5132 DM_Plex *mesh = (DM_Plex *)dm->data; 5133 DMLabel label; 5134 PetscInt pStart, pEnd; 5135 5136 PetscFunctionBegin; 5137 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5138 if (start) { 5139 PetscAssertPointer(start, 3); 5140 *start = 0; 5141 } 5142 if (end) { 5143 PetscAssertPointer(end, 4); 5144 *end = 0; 5145 } 5146 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5147 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5148 if (depth < 0) { 5149 if (start) *start = pStart; 5150 if (end) *end = pEnd; 5151 PetscFunctionReturn(PETSC_SUCCESS); 5152 } 5153 if (mesh->tr) { 5154 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5155 } else { 5156 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5157 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5158 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5159 } 5160 PetscFunctionReturn(PETSC_SUCCESS); 5161 } 5162 5163 /*@ 5164 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5165 5166 Not Collective 5167 5168 Input Parameters: 5169 + dm - The `DMPLEX` object 5170 - height - The requested height 5171 5172 Output Parameters: 5173 + start - The first point at this `height` 5174 - end - One beyond the last point at this `height` 5175 5176 Level: developer 5177 5178 Notes: 5179 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5180 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5181 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5182 5183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5184 @*/ 5185 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5186 { 5187 DMLabel label; 5188 PetscInt depth, pStart, pEnd; 5189 5190 PetscFunctionBegin; 5191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5192 if (start) { 5193 PetscAssertPointer(start, 3); 5194 *start = 0; 5195 } 5196 if (end) { 5197 PetscAssertPointer(end, 4); 5198 *end = 0; 5199 } 5200 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5201 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5202 if (height < 0) { 5203 if (start) *start = pStart; 5204 if (end) *end = pEnd; 5205 PetscFunctionReturn(PETSC_SUCCESS); 5206 } 5207 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5208 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5209 else PetscCall(DMGetDimension(dm, &depth)); 5210 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5211 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5212 PetscFunctionReturn(PETSC_SUCCESS); 5213 } 5214 5215 /*@ 5216 DMPlexGetPointDepth - Get the `depth` of a given point 5217 5218 Not Collective 5219 5220 Input Parameters: 5221 + dm - The `DMPLEX` object 5222 - point - The point 5223 5224 Output Parameter: 5225 . depth - The depth of the `point` 5226 5227 Level: intermediate 5228 5229 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5230 @*/ 5231 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5232 { 5233 PetscFunctionBegin; 5234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5235 PetscAssertPointer(depth, 3); 5236 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5237 PetscFunctionReturn(PETSC_SUCCESS); 5238 } 5239 5240 /*@ 5241 DMPlexGetPointHeight - Get the `height` of a given point 5242 5243 Not Collective 5244 5245 Input Parameters: 5246 + dm - The `DMPLEX` object 5247 - point - The point 5248 5249 Output Parameter: 5250 . height - The height of the `point` 5251 5252 Level: intermediate 5253 5254 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5255 @*/ 5256 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5257 { 5258 PetscInt n, pDepth; 5259 5260 PetscFunctionBegin; 5261 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5262 PetscAssertPointer(height, 3); 5263 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5264 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5265 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5266 PetscFunctionReturn(PETSC_SUCCESS); 5267 } 5268 5269 /*@ 5270 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5271 5272 Not Collective 5273 5274 Input Parameter: 5275 . dm - The `DMPLEX` object 5276 5277 Output Parameter: 5278 . celltypeLabel - The `DMLabel` recording cell polytope type 5279 5280 Level: developer 5281 5282 Note: 5283 This function will trigger automatica computation of cell types. This can be disabled by calling 5284 `DMCreateLabel`(dm, "celltype") beforehand. 5285 5286 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5287 @*/ 5288 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5289 { 5290 PetscFunctionBegin; 5291 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5292 PetscAssertPointer(celltypeLabel, 2); 5293 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5294 *celltypeLabel = dm->celltypeLabel; 5295 PetscFunctionReturn(PETSC_SUCCESS); 5296 } 5297 5298 /*@ 5299 DMPlexGetCellType - Get the polytope type of a given cell 5300 5301 Not Collective 5302 5303 Input Parameters: 5304 + dm - The `DMPLEX` object 5305 - cell - The cell 5306 5307 Output Parameter: 5308 . celltype - The polytope type of the cell 5309 5310 Level: intermediate 5311 5312 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5313 @*/ 5314 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5315 { 5316 DM_Plex *mesh = (DM_Plex *)dm->data; 5317 DMLabel label; 5318 PetscInt ct; 5319 5320 PetscFunctionBegin; 5321 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5322 PetscAssertPointer(celltype, 3); 5323 if (mesh->tr) { 5324 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5325 } else { 5326 PetscInt pStart, pEnd; 5327 5328 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5329 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5330 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5331 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5332 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5333 for (PetscInt p = pStart; p < pEnd; p++) { 5334 PetscCall(DMLabelGetValue(label, p, &ct)); 5335 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5336 } 5337 } 5338 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5339 if (PetscDefined(USE_DEBUG)) { 5340 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5341 PetscCall(DMLabelGetValue(label, cell, &ct)); 5342 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5343 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5344 } 5345 } 5346 PetscFunctionReturn(PETSC_SUCCESS); 5347 } 5348 5349 /*@ 5350 DMPlexSetCellType - Set the polytope type of a given cell 5351 5352 Not Collective 5353 5354 Input Parameters: 5355 + dm - The `DMPLEX` object 5356 . cell - The cell 5357 - celltype - The polytope type of the cell 5358 5359 Level: advanced 5360 5361 Note: 5362 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5363 is executed. This function will override the computed type. However, if automatic classification will not succeed 5364 and a user wants to manually specify all types, the classification must be disabled by calling 5365 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5366 5367 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5368 @*/ 5369 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5370 { 5371 DM_Plex *mesh = (DM_Plex *)dm->data; 5372 DMLabel label; 5373 PetscInt pStart, pEnd; 5374 5375 PetscFunctionBegin; 5376 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5377 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5378 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5379 PetscCall(DMLabelSetValue(label, cell, celltype)); 5380 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5381 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5382 PetscFunctionReturn(PETSC_SUCCESS); 5383 } 5384 5385 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5386 { 5387 PetscSection section, s; 5388 Mat m; 5389 PetscInt maxHeight; 5390 const char *prefix; 5391 5392 PetscFunctionBegin; 5393 PetscCall(DMClone(dm, cdm)); 5394 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5395 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5396 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5397 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5398 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5399 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5400 PetscCall(DMSetLocalSection(*cdm, section)); 5401 PetscCall(PetscSectionDestroy(§ion)); 5402 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5403 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5404 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5405 PetscCall(PetscSectionDestroy(&s)); 5406 PetscCall(MatDestroy(&m)); 5407 5408 PetscCall(DMSetNumFields(*cdm, 1)); 5409 PetscCall(DMCreateDS(*cdm)); 5410 (*cdm)->cloneOpts = PETSC_TRUE; 5411 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5412 PetscFunctionReturn(PETSC_SUCCESS); 5413 } 5414 5415 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5416 { 5417 Vec coordsLocal, cellCoordsLocal; 5418 DM coordsDM, cellCoordsDM; 5419 5420 PetscFunctionBegin; 5421 *field = NULL; 5422 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5423 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5424 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5425 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5426 if (coordsLocal && coordsDM) { 5427 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5428 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5429 } 5430 PetscFunctionReturn(PETSC_SUCCESS); 5431 } 5432 5433 /*@C 5434 DMPlexGetConeSection - Return a section which describes the layout of cone data 5435 5436 Not Collective 5437 5438 Input Parameter: 5439 . dm - The `DMPLEX` object 5440 5441 Output Parameter: 5442 . section - The `PetscSection` object 5443 5444 Level: developer 5445 5446 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5447 @*/ 5448 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5449 { 5450 DM_Plex *mesh = (DM_Plex *)dm->data; 5451 5452 PetscFunctionBegin; 5453 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5454 if (section) *section = mesh->coneSection; 5455 PetscFunctionReturn(PETSC_SUCCESS); 5456 } 5457 5458 /*@C 5459 DMPlexGetSupportSection - Return a section which describes the layout of support data 5460 5461 Not Collective 5462 5463 Input Parameter: 5464 . dm - The `DMPLEX` object 5465 5466 Output Parameter: 5467 . section - The `PetscSection` object 5468 5469 Level: developer 5470 5471 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5472 @*/ 5473 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5474 { 5475 DM_Plex *mesh = (DM_Plex *)dm->data; 5476 5477 PetscFunctionBegin; 5478 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5479 if (section) *section = mesh->supportSection; 5480 PetscFunctionReturn(PETSC_SUCCESS); 5481 } 5482 5483 /*@C 5484 DMPlexGetCones - Return cone data 5485 5486 Not Collective 5487 5488 Input Parameter: 5489 . dm - The `DMPLEX` object 5490 5491 Output Parameter: 5492 . cones - The cone for each point 5493 5494 Level: developer 5495 5496 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5497 @*/ 5498 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5499 { 5500 DM_Plex *mesh = (DM_Plex *)dm->data; 5501 5502 PetscFunctionBegin; 5503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5504 if (cones) *cones = mesh->cones; 5505 PetscFunctionReturn(PETSC_SUCCESS); 5506 } 5507 5508 /*@C 5509 DMPlexGetConeOrientations - Return cone orientation data 5510 5511 Not Collective 5512 5513 Input Parameter: 5514 . dm - The `DMPLEX` object 5515 5516 Output Parameter: 5517 . coneOrientations - The array of cone orientations for all points 5518 5519 Level: developer 5520 5521 Notes: 5522 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5523 5524 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5525 5526 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5527 @*/ 5528 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5529 { 5530 DM_Plex *mesh = (DM_Plex *)dm->data; 5531 5532 PetscFunctionBegin; 5533 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5534 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5535 PetscFunctionReturn(PETSC_SUCCESS); 5536 } 5537 5538 /******************************** FEM Support **********************************/ 5539 5540 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5541 { 5542 PetscInt depth; 5543 5544 PetscFunctionBegin; 5545 PetscCall(DMPlexGetDepth(plex, &depth)); 5546 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5547 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5548 PetscFunctionReturn(PETSC_SUCCESS); 5549 } 5550 5551 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5552 { 5553 PetscInt depth; 5554 5555 PetscFunctionBegin; 5556 PetscCall(DMPlexGetDepth(plex, &depth)); 5557 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5558 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5559 PetscFunctionReturn(PETSC_SUCCESS); 5560 } 5561 5562 /* 5563 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5564 representing a line in the section. 5565 */ 5566 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5567 { 5568 PetscFunctionBeginHot; 5569 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5570 if (line < 0) { 5571 *k = 0; 5572 *Nc = 0; 5573 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5574 *k = 1; 5575 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5576 /* An order k SEM disc has k-1 dofs on an edge */ 5577 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5578 *k = *k / *Nc + 1; 5579 } 5580 PetscFunctionReturn(PETSC_SUCCESS); 5581 } 5582 5583 /*@ 5584 5585 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5586 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5587 section provided (or the section of the `DM`). 5588 5589 Input Parameters: 5590 + dm - The `DM` 5591 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5592 - section - The `PetscSection` to reorder, or `NULL` for the default section 5593 5594 Example: 5595 A typical interpolated single-quad mesh might order points as 5596 .vb 5597 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5598 5599 v4 -- e6 -- v3 5600 | | 5601 e7 c0 e8 5602 | | 5603 v1 -- e5 -- v2 5604 .ve 5605 5606 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5607 dofs in the order of points, e.g., 5608 .vb 5609 c0 -> [0,1,2,3] 5610 v1 -> [4] 5611 ... 5612 e5 -> [8, 9] 5613 .ve 5614 5615 which corresponds to the dofs 5616 .vb 5617 6 10 11 7 5618 13 2 3 15 5619 12 0 1 14 5620 4 8 9 5 5621 .ve 5622 5623 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5624 .vb 5625 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5626 .ve 5627 5628 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5629 .vb 5630 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5631 .ve 5632 5633 Level: developer 5634 5635 Notes: 5636 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5637 degree of the basis. 5638 5639 This is required to run with libCEED. 5640 5641 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5642 @*/ 5643 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5644 { 5645 DMLabel label; 5646 PetscInt dim, depth = -1, eStart = -1, Nf; 5647 PetscBool vertexchart; 5648 5649 PetscFunctionBegin; 5650 PetscCall(DMGetDimension(dm, &dim)); 5651 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5652 if (point < 0) { 5653 PetscInt sStart, sEnd; 5654 5655 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5656 point = sEnd - sStart ? sStart : point; 5657 } 5658 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5659 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5660 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5661 if (depth == 1) { 5662 eStart = point; 5663 } else if (depth == dim) { 5664 const PetscInt *cone; 5665 5666 PetscCall(DMPlexGetCone(dm, point, &cone)); 5667 if (dim == 2) eStart = cone[0]; 5668 else if (dim == 3) { 5669 const PetscInt *cone2; 5670 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5671 eStart = cone2[0]; 5672 } 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); 5673 } 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); 5674 { /* Determine whether the chart covers all points or just vertices. */ 5675 PetscInt pStart, pEnd, cStart, cEnd; 5676 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5677 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5678 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5679 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5680 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5681 } 5682 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5683 for (PetscInt d = 1; d <= dim; d++) { 5684 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5685 PetscInt *perm; 5686 5687 for (f = 0; f < Nf; ++f) { 5688 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5689 size += PetscPowInt(k + 1, d) * Nc; 5690 } 5691 PetscCall(PetscMalloc1(size, &perm)); 5692 for (f = 0; f < Nf; ++f) { 5693 switch (d) { 5694 case 1: 5695 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5696 /* 5697 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5698 We want [ vtx0; edge of length k-1; vtx1 ] 5699 */ 5700 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5701 for (i = 0; i < k - 1; i++) 5702 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5703 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5704 foffset = offset; 5705 break; 5706 case 2: 5707 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5708 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5709 /* The SEM order is 5710 5711 v_lb, {e_b}, v_rb, 5712 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5713 v_lt, reverse {e_t}, v_rt 5714 */ 5715 { 5716 const PetscInt of = 0; 5717 const PetscInt oeb = of + PetscSqr(k - 1); 5718 const PetscInt oer = oeb + (k - 1); 5719 const PetscInt oet = oer + (k - 1); 5720 const PetscInt oel = oet + (k - 1); 5721 const PetscInt ovlb = oel + (k - 1); 5722 const PetscInt ovrb = ovlb + 1; 5723 const PetscInt ovrt = ovrb + 1; 5724 const PetscInt ovlt = ovrt + 1; 5725 PetscInt o; 5726 5727 /* bottom */ 5728 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5729 for (o = oeb; o < oer; ++o) 5730 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5731 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5732 /* middle */ 5733 for (i = 0; i < k - 1; ++i) { 5734 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5735 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5736 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5737 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5738 } 5739 /* top */ 5740 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5741 for (o = oel - 1; o >= oet; --o) 5742 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5743 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5744 foffset = offset; 5745 } 5746 break; 5747 case 3: 5748 /* The original hex closure is 5749 5750 {c, 5751 f_b, f_t, f_f, f_b, f_r, f_l, 5752 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5753 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5754 */ 5755 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5756 /* The SEM order is 5757 Bottom Slice 5758 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5759 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5760 v_blb, {e_bb}, v_brb, 5761 5762 Middle Slice (j) 5763 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5764 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5765 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5766 5767 Top Slice 5768 v_tlf, {e_tf}, v_trf, 5769 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5770 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5771 */ 5772 { 5773 const PetscInt oc = 0; 5774 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5775 const PetscInt oft = ofb + PetscSqr(k - 1); 5776 const PetscInt off = oft + PetscSqr(k - 1); 5777 const PetscInt ofk = off + PetscSqr(k - 1); 5778 const PetscInt ofr = ofk + PetscSqr(k - 1); 5779 const PetscInt ofl = ofr + PetscSqr(k - 1); 5780 const PetscInt oebl = ofl + PetscSqr(k - 1); 5781 const PetscInt oebb = oebl + (k - 1); 5782 const PetscInt oebr = oebb + (k - 1); 5783 const PetscInt oebf = oebr + (k - 1); 5784 const PetscInt oetf = oebf + (k - 1); 5785 const PetscInt oetr = oetf + (k - 1); 5786 const PetscInt oetb = oetr + (k - 1); 5787 const PetscInt oetl = oetb + (k - 1); 5788 const PetscInt oerf = oetl + (k - 1); 5789 const PetscInt oelf = oerf + (k - 1); 5790 const PetscInt oelb = oelf + (k - 1); 5791 const PetscInt oerb = oelb + (k - 1); 5792 const PetscInt ovblf = oerb + (k - 1); 5793 const PetscInt ovblb = ovblf + 1; 5794 const PetscInt ovbrb = ovblb + 1; 5795 const PetscInt ovbrf = ovbrb + 1; 5796 const PetscInt ovtlf = ovbrf + 1; 5797 const PetscInt ovtrf = ovtlf + 1; 5798 const PetscInt ovtrb = ovtrf + 1; 5799 const PetscInt ovtlb = ovtrb + 1; 5800 PetscInt o, n; 5801 5802 /* Bottom Slice */ 5803 /* bottom */ 5804 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5805 for (o = oetf - 1; o >= oebf; --o) 5806 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5807 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5808 /* middle */ 5809 for (i = 0; i < k - 1; ++i) { 5810 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5811 for (n = 0; n < k - 1; ++n) { 5812 o = ofb + n * (k - 1) + i; 5813 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5814 } 5815 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5816 } 5817 /* top */ 5818 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5819 for (o = oebb; o < oebr; ++o) 5820 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5821 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5822 5823 /* Middle Slice */ 5824 for (j = 0; j < k - 1; ++j) { 5825 /* bottom */ 5826 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5827 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5828 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5829 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5830 /* middle */ 5831 for (i = 0; i < k - 1; ++i) { 5832 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5833 for (n = 0; n < k - 1; ++n) 5834 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5835 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5836 } 5837 /* top */ 5838 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5839 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5840 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5841 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5842 } 5843 5844 /* Top Slice */ 5845 /* bottom */ 5846 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5847 for (o = oetf; o < oetr; ++o) 5848 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5849 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5850 /* middle */ 5851 for (i = 0; i < k - 1; ++i) { 5852 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5853 for (n = 0; n < k - 1; ++n) 5854 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5855 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5856 } 5857 /* top */ 5858 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5859 for (o = oetl - 1; o >= oetb; --o) 5860 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5861 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5862 5863 foffset = offset; 5864 } 5865 break; 5866 default: 5867 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5868 } 5869 } 5870 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5871 /* Check permutation */ 5872 { 5873 PetscInt *check; 5874 5875 PetscCall(PetscMalloc1(size, &check)); 5876 for (i = 0; i < size; ++i) { 5877 check[i] = -1; 5878 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5879 } 5880 for (i = 0; i < size; ++i) check[perm[i]] = i; 5881 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5882 PetscCall(PetscFree(check)); 5883 } 5884 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5885 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5886 PetscInt *loc_perm; 5887 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5888 for (PetscInt i = 0; i < size; i++) { 5889 loc_perm[i] = perm[i]; 5890 loc_perm[size + i] = size + perm[i]; 5891 } 5892 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5893 } 5894 } 5895 PetscFunctionReturn(PETSC_SUCCESS); 5896 } 5897 5898 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5899 { 5900 PetscDS prob; 5901 PetscInt depth, Nf, h; 5902 DMLabel label; 5903 5904 PetscFunctionBeginHot; 5905 PetscCall(DMGetDS(dm, &prob)); 5906 Nf = prob->Nf; 5907 label = dm->depthLabel; 5908 *dspace = NULL; 5909 if (field < Nf) { 5910 PetscObject disc = prob->disc[field]; 5911 5912 if (disc->classid == PETSCFE_CLASSID) { 5913 PetscDualSpace dsp; 5914 5915 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5916 PetscCall(DMLabelGetNumValues(label, &depth)); 5917 PetscCall(DMLabelGetValue(label, point, &h)); 5918 h = depth - 1 - h; 5919 if (h) { 5920 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5921 } else { 5922 *dspace = dsp; 5923 } 5924 } 5925 } 5926 PetscFunctionReturn(PETSC_SUCCESS); 5927 } 5928 5929 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5930 { 5931 PetscScalar *array; 5932 const PetscScalar *vArray; 5933 const PetscInt *cone, *coneO; 5934 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5935 5936 PetscFunctionBeginHot; 5937 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5938 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5939 PetscCall(DMPlexGetCone(dm, point, &cone)); 5940 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5941 if (!values || !*values) { 5942 if ((point >= pStart) && (point < pEnd)) { 5943 PetscInt dof; 5944 5945 PetscCall(PetscSectionGetDof(section, point, &dof)); 5946 size += dof; 5947 } 5948 for (p = 0; p < numPoints; ++p) { 5949 const PetscInt cp = cone[p]; 5950 PetscInt dof; 5951 5952 if ((cp < pStart) || (cp >= pEnd)) continue; 5953 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5954 size += dof; 5955 } 5956 if (!values) { 5957 if (csize) *csize = size; 5958 PetscFunctionReturn(PETSC_SUCCESS); 5959 } 5960 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5961 } else { 5962 array = *values; 5963 } 5964 size = 0; 5965 PetscCall(VecGetArrayRead(v, &vArray)); 5966 if ((point >= pStart) && (point < pEnd)) { 5967 PetscInt dof, off, d; 5968 const PetscScalar *varr; 5969 5970 PetscCall(PetscSectionGetDof(section, point, &dof)); 5971 PetscCall(PetscSectionGetOffset(section, point, &off)); 5972 varr = &vArray[off]; 5973 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5974 size += dof; 5975 } 5976 for (p = 0; p < numPoints; ++p) { 5977 const PetscInt cp = cone[p]; 5978 PetscInt o = coneO[p]; 5979 PetscInt dof, off, d; 5980 const PetscScalar *varr; 5981 5982 if ((cp < pStart) || (cp >= pEnd)) continue; 5983 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5984 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5985 varr = &vArray[off]; 5986 if (o >= 0) { 5987 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5988 } else { 5989 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5990 } 5991 size += dof; 5992 } 5993 PetscCall(VecRestoreArrayRead(v, &vArray)); 5994 if (!*values) { 5995 if (csize) *csize = size; 5996 *values = array; 5997 } else { 5998 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5999 *csize = size; 6000 } 6001 PetscFunctionReturn(PETSC_SUCCESS); 6002 } 6003 6004 /* Compress out points not in the section */ 6005 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6006 { 6007 const PetscInt np = *numPoints; 6008 PetscInt pStart, pEnd, p, q; 6009 6010 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6011 for (p = 0, q = 0; p < np; ++p) { 6012 const PetscInt r = points[p * 2]; 6013 if ((r >= pStart) && (r < pEnd)) { 6014 points[q * 2] = r; 6015 points[q * 2 + 1] = points[p * 2 + 1]; 6016 ++q; 6017 } 6018 } 6019 *numPoints = q; 6020 return PETSC_SUCCESS; 6021 } 6022 6023 /* Compressed closure does not apply closure permutation */ 6024 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6025 { 6026 const PetscInt *cla = NULL; 6027 PetscInt np, *pts = NULL; 6028 6029 PetscFunctionBeginHot; 6030 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6031 if (!ornt && *clPoints) { 6032 PetscInt dof, off; 6033 6034 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6035 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6036 PetscCall(ISGetIndices(*clPoints, &cla)); 6037 np = dof / 2; 6038 pts = (PetscInt *)&cla[off]; 6039 } else { 6040 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6041 PetscCall(CompressPoints_Private(section, &np, pts)); 6042 } 6043 *numPoints = np; 6044 *points = pts; 6045 *clp = cla; 6046 PetscFunctionReturn(PETSC_SUCCESS); 6047 } 6048 6049 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6050 { 6051 PetscFunctionBeginHot; 6052 if (!*clPoints) { 6053 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6054 } else { 6055 PetscCall(ISRestoreIndices(*clPoints, clp)); 6056 } 6057 *numPoints = 0; 6058 *points = NULL; 6059 *clSec = NULL; 6060 *clPoints = NULL; 6061 *clp = NULL; 6062 PetscFunctionReturn(PETSC_SUCCESS); 6063 } 6064 6065 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6066 { 6067 PetscInt offset = 0, p; 6068 const PetscInt **perms = NULL; 6069 const PetscScalar **flips = NULL; 6070 6071 PetscFunctionBeginHot; 6072 *size = 0; 6073 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6074 for (p = 0; p < numPoints; p++) { 6075 const PetscInt point = points[2 * p]; 6076 const PetscInt *perm = perms ? perms[p] : NULL; 6077 const PetscScalar *flip = flips ? flips[p] : NULL; 6078 PetscInt dof, off, d; 6079 const PetscScalar *varr; 6080 6081 PetscCall(PetscSectionGetDof(section, point, &dof)); 6082 PetscCall(PetscSectionGetOffset(section, point, &off)); 6083 varr = &vArray[off]; 6084 if (clperm) { 6085 if (perm) { 6086 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6087 } else { 6088 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6089 } 6090 if (flip) { 6091 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6092 } 6093 } else { 6094 if (perm) { 6095 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6096 } else { 6097 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6098 } 6099 if (flip) { 6100 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6101 } 6102 } 6103 offset += dof; 6104 } 6105 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6106 *size = offset; 6107 PetscFunctionReturn(PETSC_SUCCESS); 6108 } 6109 6110 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[]) 6111 { 6112 PetscInt offset = 0, f; 6113 6114 PetscFunctionBeginHot; 6115 *size = 0; 6116 for (f = 0; f < numFields; ++f) { 6117 PetscInt p; 6118 const PetscInt **perms = NULL; 6119 const PetscScalar **flips = NULL; 6120 6121 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6122 for (p = 0; p < numPoints; p++) { 6123 const PetscInt point = points[2 * p]; 6124 PetscInt fdof, foff, b; 6125 const PetscScalar *varr; 6126 const PetscInt *perm = perms ? perms[p] : NULL; 6127 const PetscScalar *flip = flips ? flips[p] : NULL; 6128 6129 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6130 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6131 varr = &vArray[foff]; 6132 if (clperm) { 6133 if (perm) { 6134 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6135 } else { 6136 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6137 } 6138 if (flip) { 6139 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6140 } 6141 } else { 6142 if (perm) { 6143 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6144 } else { 6145 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6146 } 6147 if (flip) { 6148 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6149 } 6150 } 6151 offset += fdof; 6152 } 6153 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6154 } 6155 *size = offset; 6156 PetscFunctionReturn(PETSC_SUCCESS); 6157 } 6158 6159 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6160 { 6161 PetscSection clSection; 6162 IS clPoints; 6163 PetscInt *points = NULL; 6164 const PetscInt *clp, *perm = NULL; 6165 PetscInt depth, numFields, numPoints, asize; 6166 6167 PetscFunctionBeginHot; 6168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6169 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6170 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6171 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6172 PetscCall(DMPlexGetDepth(dm, &depth)); 6173 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6174 if (depth == 1 && numFields < 2) { 6175 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6176 PetscFunctionReturn(PETSC_SUCCESS); 6177 } 6178 /* Get points */ 6179 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6180 /* Get sizes */ 6181 asize = 0; 6182 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6183 PetscInt dof; 6184 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6185 asize += dof; 6186 } 6187 if (values) { 6188 const PetscScalar *vArray; 6189 PetscInt size; 6190 6191 if (*values) { 6192 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); 6193 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6194 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6195 PetscCall(VecGetArrayRead(v, &vArray)); 6196 /* Get values */ 6197 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6198 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6199 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6200 /* Cleanup array */ 6201 PetscCall(VecRestoreArrayRead(v, &vArray)); 6202 } 6203 if (csize) *csize = asize; 6204 /* Cleanup points */ 6205 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6206 PetscFunctionReturn(PETSC_SUCCESS); 6207 } 6208 6209 /*@C 6210 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6211 6212 Not collective 6213 6214 Input Parameters: 6215 + dm - The `DM` 6216 . section - The section describing the layout in `v`, or `NULL` to use the default section 6217 . v - The local vector 6218 - point - The point in the `DM` 6219 6220 Input/Output Parameters: 6221 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6222 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6223 if the user provided `NULL`, it is a borrowed array and should not be freed 6224 6225 Level: intermediate 6226 6227 Notes: 6228 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6229 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6230 assembly function, and a user may already have allocated storage for this operation. 6231 6232 A typical use could be 6233 .vb 6234 values = NULL; 6235 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6236 for (cl = 0; cl < clSize; ++cl) { 6237 <Compute on closure> 6238 } 6239 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6240 .ve 6241 or 6242 .vb 6243 PetscMalloc1(clMaxSize, &values); 6244 for (p = pStart; p < pEnd; ++p) { 6245 clSize = clMaxSize; 6246 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6247 for (cl = 0; cl < clSize; ++cl) { 6248 <Compute on closure> 6249 } 6250 } 6251 PetscFree(values); 6252 .ve 6253 6254 Fortran Notes: 6255 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6256 6257 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6258 @*/ 6259 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6260 { 6261 PetscFunctionBeginHot; 6262 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6263 PetscFunctionReturn(PETSC_SUCCESS); 6264 } 6265 6266 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6267 { 6268 DMLabel depthLabel; 6269 PetscSection clSection; 6270 IS clPoints; 6271 PetscScalar *array; 6272 const PetscScalar *vArray; 6273 PetscInt *points = NULL; 6274 const PetscInt *clp, *perm = NULL; 6275 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6276 6277 PetscFunctionBeginHot; 6278 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6279 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6280 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6281 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6282 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6283 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6284 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6285 if (mdepth == 1 && numFields < 2) { 6286 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6287 PetscFunctionReturn(PETSC_SUCCESS); 6288 } 6289 /* Get points */ 6290 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6291 for (clsize = 0, p = 0; p < Np; p++) { 6292 PetscInt dof; 6293 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6294 clsize += dof; 6295 } 6296 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6297 /* Filter points */ 6298 for (p = 0; p < numPoints * 2; p += 2) { 6299 PetscInt dep; 6300 6301 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6302 if (dep != depth) continue; 6303 points[Np * 2 + 0] = points[p]; 6304 points[Np * 2 + 1] = points[p + 1]; 6305 ++Np; 6306 } 6307 /* Get array */ 6308 if (!values || !*values) { 6309 PetscInt asize = 0, dof; 6310 6311 for (p = 0; p < Np * 2; p += 2) { 6312 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6313 asize += dof; 6314 } 6315 if (!values) { 6316 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6317 if (csize) *csize = asize; 6318 PetscFunctionReturn(PETSC_SUCCESS); 6319 } 6320 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6321 } else { 6322 array = *values; 6323 } 6324 PetscCall(VecGetArrayRead(v, &vArray)); 6325 /* Get values */ 6326 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6327 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6328 /* Cleanup points */ 6329 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6330 /* Cleanup array */ 6331 PetscCall(VecRestoreArrayRead(v, &vArray)); 6332 if (!*values) { 6333 if (csize) *csize = size; 6334 *values = array; 6335 } else { 6336 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6337 *csize = size; 6338 } 6339 PetscFunctionReturn(PETSC_SUCCESS); 6340 } 6341 6342 /*@C 6343 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6344 6345 Not collective 6346 6347 Input Parameters: 6348 + dm - The `DM` 6349 . section - The section describing the layout in `v`, or `NULL` to use the default section 6350 . v - The local vector 6351 . point - The point in the `DM` 6352 . csize - The number of values in the closure, or `NULL` 6353 - values - The array of values, which is a borrowed array and should not be freed 6354 6355 Level: intermediate 6356 6357 Note: 6358 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6359 6360 Fortran Notes: 6361 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6362 6363 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6364 @*/ 6365 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6366 { 6367 PetscInt size = 0; 6368 6369 PetscFunctionBegin; 6370 /* Should work without recalculating size */ 6371 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6372 *values = NULL; 6373 PetscFunctionReturn(PETSC_SUCCESS); 6374 } 6375 6376 static inline void add(PetscScalar *x, PetscScalar y) 6377 { 6378 *x += y; 6379 } 6380 static inline void insert(PetscScalar *x, PetscScalar y) 6381 { 6382 *x = y; 6383 } 6384 6385 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[]) 6386 { 6387 PetscInt cdof; /* The number of constraints on this point */ 6388 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6389 PetscScalar *a; 6390 PetscInt off, cind = 0, k; 6391 6392 PetscFunctionBegin; 6393 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6394 PetscCall(PetscSectionGetOffset(section, point, &off)); 6395 a = &array[off]; 6396 if (!cdof || setBC) { 6397 if (clperm) { 6398 if (perm) { 6399 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6400 } else { 6401 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6402 } 6403 } else { 6404 if (perm) { 6405 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6406 } else { 6407 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6408 } 6409 } 6410 } else { 6411 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6412 if (clperm) { 6413 if (perm) { 6414 for (k = 0; k < dof; ++k) { 6415 if ((cind < cdof) && (k == cdofs[cind])) { 6416 ++cind; 6417 continue; 6418 } 6419 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6420 } 6421 } else { 6422 for (k = 0; k < dof; ++k) { 6423 if ((cind < cdof) && (k == cdofs[cind])) { 6424 ++cind; 6425 continue; 6426 } 6427 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6428 } 6429 } 6430 } else { 6431 if (perm) { 6432 for (k = 0; k < dof; ++k) { 6433 if ((cind < cdof) && (k == cdofs[cind])) { 6434 ++cind; 6435 continue; 6436 } 6437 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6438 } 6439 } else { 6440 for (k = 0; k < dof; ++k) { 6441 if ((cind < cdof) && (k == cdofs[cind])) { 6442 ++cind; 6443 continue; 6444 } 6445 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6446 } 6447 } 6448 } 6449 } 6450 PetscFunctionReturn(PETSC_SUCCESS); 6451 } 6452 6453 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[]) 6454 { 6455 PetscInt cdof; /* The number of constraints on this point */ 6456 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6457 PetscScalar *a; 6458 PetscInt off, cind = 0, k; 6459 6460 PetscFunctionBegin; 6461 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6462 PetscCall(PetscSectionGetOffset(section, point, &off)); 6463 a = &array[off]; 6464 if (cdof) { 6465 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6466 if (clperm) { 6467 if (perm) { 6468 for (k = 0; k < dof; ++k) { 6469 if ((cind < cdof) && (k == cdofs[cind])) { 6470 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6471 cind++; 6472 } 6473 } 6474 } else { 6475 for (k = 0; k < dof; ++k) { 6476 if ((cind < cdof) && (k == cdofs[cind])) { 6477 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6478 cind++; 6479 } 6480 } 6481 } 6482 } else { 6483 if (perm) { 6484 for (k = 0; k < dof; ++k) { 6485 if ((cind < cdof) && (k == cdofs[cind])) { 6486 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6487 cind++; 6488 } 6489 } 6490 } else { 6491 for (k = 0; k < dof; ++k) { 6492 if ((cind < cdof) && (k == cdofs[cind])) { 6493 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6494 cind++; 6495 } 6496 } 6497 } 6498 } 6499 } 6500 PetscFunctionReturn(PETSC_SUCCESS); 6501 } 6502 6503 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[]) 6504 { 6505 PetscScalar *a; 6506 PetscInt fdof, foff, fcdof, foffset = *offset; 6507 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6508 PetscInt cind = 0, b; 6509 6510 PetscFunctionBegin; 6511 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6512 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6513 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6514 a = &array[foff]; 6515 if (!fcdof || setBC) { 6516 if (clperm) { 6517 if (perm) { 6518 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6519 } else { 6520 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6521 } 6522 } else { 6523 if (perm) { 6524 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6525 } else { 6526 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6527 } 6528 } 6529 } else { 6530 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6531 if (clperm) { 6532 if (perm) { 6533 for (b = 0; b < fdof; b++) { 6534 if ((cind < fcdof) && (b == fcdofs[cind])) { 6535 ++cind; 6536 continue; 6537 } 6538 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6539 } 6540 } else { 6541 for (b = 0; b < fdof; b++) { 6542 if ((cind < fcdof) && (b == fcdofs[cind])) { 6543 ++cind; 6544 continue; 6545 } 6546 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6547 } 6548 } 6549 } else { 6550 if (perm) { 6551 for (b = 0; b < fdof; b++) { 6552 if ((cind < fcdof) && (b == fcdofs[cind])) { 6553 ++cind; 6554 continue; 6555 } 6556 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6557 } 6558 } else { 6559 for (b = 0; b < fdof; b++) { 6560 if ((cind < fcdof) && (b == fcdofs[cind])) { 6561 ++cind; 6562 continue; 6563 } 6564 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6565 } 6566 } 6567 } 6568 } 6569 *offset += fdof; 6570 PetscFunctionReturn(PETSC_SUCCESS); 6571 } 6572 6573 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[]) 6574 { 6575 PetscScalar *a; 6576 PetscInt fdof, foff, fcdof, foffset = *offset; 6577 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6578 PetscInt Nc, cind = 0, ncind = 0, b; 6579 PetscBool ncSet, fcSet; 6580 6581 PetscFunctionBegin; 6582 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6583 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6584 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6585 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6586 a = &array[foff]; 6587 if (fcdof) { 6588 /* We just override fcdof and fcdofs with Ncc and comps */ 6589 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6590 if (clperm) { 6591 if (perm) { 6592 if (comps) { 6593 for (b = 0; b < fdof; b++) { 6594 ncSet = fcSet = PETSC_FALSE; 6595 if (b % Nc == comps[ncind]) { 6596 ncind = (ncind + 1) % Ncc; 6597 ncSet = PETSC_TRUE; 6598 } 6599 if ((cind < fcdof) && (b == fcdofs[cind])) { 6600 ++cind; 6601 fcSet = PETSC_TRUE; 6602 } 6603 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6604 } 6605 } else { 6606 for (b = 0; b < fdof; b++) { 6607 if ((cind < fcdof) && (b == fcdofs[cind])) { 6608 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6609 ++cind; 6610 } 6611 } 6612 } 6613 } else { 6614 if (comps) { 6615 for (b = 0; b < fdof; b++) { 6616 ncSet = fcSet = PETSC_FALSE; 6617 if (b % Nc == comps[ncind]) { 6618 ncind = (ncind + 1) % Ncc; 6619 ncSet = PETSC_TRUE; 6620 } 6621 if ((cind < fcdof) && (b == fcdofs[cind])) { 6622 ++cind; 6623 fcSet = PETSC_TRUE; 6624 } 6625 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6626 } 6627 } else { 6628 for (b = 0; b < fdof; b++) { 6629 if ((cind < fcdof) && (b == fcdofs[cind])) { 6630 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6631 ++cind; 6632 } 6633 } 6634 } 6635 } 6636 } else { 6637 if (perm) { 6638 if (comps) { 6639 for (b = 0; b < fdof; b++) { 6640 ncSet = fcSet = PETSC_FALSE; 6641 if (b % Nc == comps[ncind]) { 6642 ncind = (ncind + 1) % Ncc; 6643 ncSet = PETSC_TRUE; 6644 } 6645 if ((cind < fcdof) && (b == fcdofs[cind])) { 6646 ++cind; 6647 fcSet = PETSC_TRUE; 6648 } 6649 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6650 } 6651 } else { 6652 for (b = 0; b < fdof; b++) { 6653 if ((cind < fcdof) && (b == fcdofs[cind])) { 6654 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6655 ++cind; 6656 } 6657 } 6658 } 6659 } else { 6660 if (comps) { 6661 for (b = 0; b < fdof; b++) { 6662 ncSet = fcSet = PETSC_FALSE; 6663 if (b % Nc == comps[ncind]) { 6664 ncind = (ncind + 1) % Ncc; 6665 ncSet = PETSC_TRUE; 6666 } 6667 if ((cind < fcdof) && (b == fcdofs[cind])) { 6668 ++cind; 6669 fcSet = PETSC_TRUE; 6670 } 6671 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6672 } 6673 } else { 6674 for (b = 0; b < fdof; b++) { 6675 if ((cind < fcdof) && (b == fcdofs[cind])) { 6676 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6677 ++cind; 6678 } 6679 } 6680 } 6681 } 6682 } 6683 } 6684 *offset += fdof; 6685 PetscFunctionReturn(PETSC_SUCCESS); 6686 } 6687 6688 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6689 { 6690 PetscScalar *array; 6691 const PetscInt *cone, *coneO; 6692 PetscInt pStart, pEnd, p, numPoints, off, dof; 6693 6694 PetscFunctionBeginHot; 6695 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6696 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6697 PetscCall(DMPlexGetCone(dm, point, &cone)); 6698 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6699 PetscCall(VecGetArray(v, &array)); 6700 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6701 const PetscInt cp = !p ? point : cone[p - 1]; 6702 const PetscInt o = !p ? 0 : coneO[p - 1]; 6703 6704 if ((cp < pStart) || (cp >= pEnd)) { 6705 dof = 0; 6706 continue; 6707 } 6708 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6709 /* ADD_VALUES */ 6710 { 6711 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6712 PetscScalar *a; 6713 PetscInt cdof, coff, cind = 0, k; 6714 6715 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6716 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6717 a = &array[coff]; 6718 if (!cdof) { 6719 if (o >= 0) { 6720 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6721 } else { 6722 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6723 } 6724 } else { 6725 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6726 if (o >= 0) { 6727 for (k = 0; k < dof; ++k) { 6728 if ((cind < cdof) && (k == cdofs[cind])) { 6729 ++cind; 6730 continue; 6731 } 6732 a[k] += values[off + k]; 6733 } 6734 } else { 6735 for (k = 0; k < dof; ++k) { 6736 if ((cind < cdof) && (k == cdofs[cind])) { 6737 ++cind; 6738 continue; 6739 } 6740 a[k] += values[off + dof - k - 1]; 6741 } 6742 } 6743 } 6744 } 6745 } 6746 PetscCall(VecRestoreArray(v, &array)); 6747 PetscFunctionReturn(PETSC_SUCCESS); 6748 } 6749 6750 /*@C 6751 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6752 6753 Not collective 6754 6755 Input Parameters: 6756 + dm - The `DM` 6757 . section - The section describing the layout in `v`, or `NULL` to use the default section 6758 . v - The local vector 6759 . point - The point in the `DM` 6760 . values - The array of values 6761 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6762 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6763 6764 Level: intermediate 6765 6766 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6767 @*/ 6768 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6769 { 6770 PetscSection clSection; 6771 IS clPoints; 6772 PetscScalar *array; 6773 PetscInt *points = NULL; 6774 const PetscInt *clp, *clperm = NULL; 6775 PetscInt depth, numFields, numPoints, p, clsize; 6776 6777 PetscFunctionBeginHot; 6778 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6779 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6780 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6781 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6782 PetscCall(DMPlexGetDepth(dm, &depth)); 6783 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6784 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6785 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6786 PetscFunctionReturn(PETSC_SUCCESS); 6787 } 6788 /* Get points */ 6789 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6790 for (clsize = 0, p = 0; p < numPoints; p++) { 6791 PetscInt dof; 6792 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6793 clsize += dof; 6794 } 6795 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6796 /* Get array */ 6797 PetscCall(VecGetArray(v, &array)); 6798 /* Get values */ 6799 if (numFields > 0) { 6800 PetscInt offset = 0, f; 6801 for (f = 0; f < numFields; ++f) { 6802 const PetscInt **perms = NULL; 6803 const PetscScalar **flips = NULL; 6804 6805 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6806 switch (mode) { 6807 case INSERT_VALUES: 6808 for (p = 0; p < numPoints; p++) { 6809 const PetscInt point = points[2 * p]; 6810 const PetscInt *perm = perms ? perms[p] : NULL; 6811 const PetscScalar *flip = flips ? flips[p] : NULL; 6812 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6813 } 6814 break; 6815 case INSERT_ALL_VALUES: 6816 for (p = 0; p < numPoints; p++) { 6817 const PetscInt point = points[2 * p]; 6818 const PetscInt *perm = perms ? perms[p] : NULL; 6819 const PetscScalar *flip = flips ? flips[p] : NULL; 6820 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6821 } 6822 break; 6823 case INSERT_BC_VALUES: 6824 for (p = 0; p < numPoints; p++) { 6825 const PetscInt point = points[2 * p]; 6826 const PetscInt *perm = perms ? perms[p] : NULL; 6827 const PetscScalar *flip = flips ? flips[p] : NULL; 6828 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6829 } 6830 break; 6831 case ADD_VALUES: 6832 for (p = 0; p < numPoints; p++) { 6833 const PetscInt point = points[2 * p]; 6834 const PetscInt *perm = perms ? perms[p] : NULL; 6835 const PetscScalar *flip = flips ? flips[p] : NULL; 6836 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6837 } 6838 break; 6839 case ADD_ALL_VALUES: 6840 for (p = 0; p < numPoints; p++) { 6841 const PetscInt point = points[2 * p]; 6842 const PetscInt *perm = perms ? perms[p] : NULL; 6843 const PetscScalar *flip = flips ? flips[p] : NULL; 6844 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6845 } 6846 break; 6847 case ADD_BC_VALUES: 6848 for (p = 0; p < numPoints; p++) { 6849 const PetscInt point = points[2 * p]; 6850 const PetscInt *perm = perms ? perms[p] : NULL; 6851 const PetscScalar *flip = flips ? flips[p] : NULL; 6852 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6853 } 6854 break; 6855 default: 6856 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6857 } 6858 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6859 } 6860 } else { 6861 PetscInt dof, off; 6862 const PetscInt **perms = NULL; 6863 const PetscScalar **flips = NULL; 6864 6865 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6866 switch (mode) { 6867 case INSERT_VALUES: 6868 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6869 const PetscInt point = points[2 * p]; 6870 const PetscInt *perm = perms ? perms[p] : NULL; 6871 const PetscScalar *flip = flips ? flips[p] : NULL; 6872 PetscCall(PetscSectionGetDof(section, point, &dof)); 6873 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6874 } 6875 break; 6876 case INSERT_ALL_VALUES: 6877 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6878 const PetscInt point = points[2 * p]; 6879 const PetscInt *perm = perms ? perms[p] : NULL; 6880 const PetscScalar *flip = flips ? flips[p] : NULL; 6881 PetscCall(PetscSectionGetDof(section, point, &dof)); 6882 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6883 } 6884 break; 6885 case INSERT_BC_VALUES: 6886 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6887 const PetscInt point = points[2 * p]; 6888 const PetscInt *perm = perms ? perms[p] : NULL; 6889 const PetscScalar *flip = flips ? flips[p] : NULL; 6890 PetscCall(PetscSectionGetDof(section, point, &dof)); 6891 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6892 } 6893 break; 6894 case ADD_VALUES: 6895 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6896 const PetscInt point = points[2 * p]; 6897 const PetscInt *perm = perms ? perms[p] : NULL; 6898 const PetscScalar *flip = flips ? flips[p] : NULL; 6899 PetscCall(PetscSectionGetDof(section, point, &dof)); 6900 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6901 } 6902 break; 6903 case ADD_ALL_VALUES: 6904 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6905 const PetscInt point = points[2 * p]; 6906 const PetscInt *perm = perms ? perms[p] : NULL; 6907 const PetscScalar *flip = flips ? flips[p] : NULL; 6908 PetscCall(PetscSectionGetDof(section, point, &dof)); 6909 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6910 } 6911 break; 6912 case ADD_BC_VALUES: 6913 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6914 const PetscInt point = points[2 * p]; 6915 const PetscInt *perm = perms ? perms[p] : NULL; 6916 const PetscScalar *flip = flips ? flips[p] : NULL; 6917 PetscCall(PetscSectionGetDof(section, point, &dof)); 6918 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6919 } 6920 break; 6921 default: 6922 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6923 } 6924 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6925 } 6926 /* Cleanup points */ 6927 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6928 /* Cleanup array */ 6929 PetscCall(VecRestoreArray(v, &array)); 6930 PetscFunctionReturn(PETSC_SUCCESS); 6931 } 6932 6933 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6934 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6935 { 6936 PetscFunctionBegin; 6937 *contains = PETSC_TRUE; 6938 if (label) { 6939 PetscInt fdof; 6940 6941 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6942 if (!*contains) { 6943 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6944 *offset += fdof; 6945 PetscFunctionReturn(PETSC_SUCCESS); 6946 } 6947 } 6948 PetscFunctionReturn(PETSC_SUCCESS); 6949 } 6950 6951 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6952 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) 6953 { 6954 PetscSection clSection; 6955 IS clPoints; 6956 PetscScalar *array; 6957 PetscInt *points = NULL; 6958 const PetscInt *clp; 6959 PetscInt numFields, numPoints, p; 6960 PetscInt offset = 0, f; 6961 6962 PetscFunctionBeginHot; 6963 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6964 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6965 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6966 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6967 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6968 /* Get points */ 6969 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6970 /* Get array */ 6971 PetscCall(VecGetArray(v, &array)); 6972 /* Get values */ 6973 for (f = 0; f < numFields; ++f) { 6974 const PetscInt **perms = NULL; 6975 const PetscScalar **flips = NULL; 6976 PetscBool contains; 6977 6978 if (!fieldActive[f]) { 6979 for (p = 0; p < numPoints * 2; p += 2) { 6980 PetscInt fdof; 6981 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6982 offset += fdof; 6983 } 6984 continue; 6985 } 6986 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6987 switch (mode) { 6988 case INSERT_VALUES: 6989 for (p = 0; p < numPoints; p++) { 6990 const PetscInt point = points[2 * p]; 6991 const PetscInt *perm = perms ? perms[p] : NULL; 6992 const PetscScalar *flip = flips ? flips[p] : NULL; 6993 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6994 if (!contains) continue; 6995 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6996 } 6997 break; 6998 case INSERT_ALL_VALUES: 6999 for (p = 0; p < numPoints; p++) { 7000 const PetscInt point = points[2 * p]; 7001 const PetscInt *perm = perms ? perms[p] : NULL; 7002 const PetscScalar *flip = flips ? flips[p] : NULL; 7003 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7004 if (!contains) continue; 7005 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7006 } 7007 break; 7008 case INSERT_BC_VALUES: 7009 for (p = 0; p < numPoints; p++) { 7010 const PetscInt point = points[2 * p]; 7011 const PetscInt *perm = perms ? perms[p] : NULL; 7012 const PetscScalar *flip = flips ? flips[p] : NULL; 7013 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7014 if (!contains) continue; 7015 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7016 } 7017 break; 7018 case ADD_VALUES: 7019 for (p = 0; p < numPoints; p++) { 7020 const PetscInt point = points[2 * p]; 7021 const PetscInt *perm = perms ? perms[p] : NULL; 7022 const PetscScalar *flip = flips ? flips[p] : NULL; 7023 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7024 if (!contains) continue; 7025 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7026 } 7027 break; 7028 case ADD_ALL_VALUES: 7029 for (p = 0; p < numPoints; p++) { 7030 const PetscInt point = points[2 * p]; 7031 const PetscInt *perm = perms ? perms[p] : NULL; 7032 const PetscScalar *flip = flips ? flips[p] : NULL; 7033 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7034 if (!contains) continue; 7035 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7036 } 7037 break; 7038 default: 7039 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7040 } 7041 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7042 } 7043 /* Cleanup points */ 7044 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7045 /* Cleanup array */ 7046 PetscCall(VecRestoreArray(v, &array)); 7047 PetscFunctionReturn(PETSC_SUCCESS); 7048 } 7049 7050 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7051 { 7052 PetscMPIInt rank; 7053 PetscInt i, j; 7054 7055 PetscFunctionBegin; 7056 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7057 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7058 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7059 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7060 numCIndices = numCIndices ? numCIndices : numRIndices; 7061 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7062 for (i = 0; i < numRIndices; i++) { 7063 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7064 for (j = 0; j < numCIndices; j++) { 7065 #if defined(PETSC_USE_COMPLEX) 7066 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7067 #else 7068 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7069 #endif 7070 } 7071 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7072 } 7073 PetscFunctionReturn(PETSC_SUCCESS); 7074 } 7075 7076 /* 7077 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7078 7079 Input Parameters: 7080 + section - The section for this data layout 7081 . islocal - Is the section (and thus indices being requested) local or global? 7082 . point - The point contributing dofs with these indices 7083 . off - The global offset of this point 7084 . loff - The local offset of each field 7085 . setBC - The flag determining whether to include indices of boundary values 7086 . perm - A permutation of the dofs on this point, or NULL 7087 - indperm - A permutation of the entire indices array, or NULL 7088 7089 Output Parameter: 7090 . indices - Indices for dofs on this point 7091 7092 Level: developer 7093 7094 Note: The indices could be local or global, depending on the value of 'off'. 7095 */ 7096 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7097 { 7098 PetscInt dof; /* The number of unknowns on this point */ 7099 PetscInt cdof; /* The number of constraints on this point */ 7100 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7101 PetscInt cind = 0, k; 7102 7103 PetscFunctionBegin; 7104 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7105 PetscCall(PetscSectionGetDof(section, point, &dof)); 7106 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7107 if (!cdof || setBC) { 7108 for (k = 0; k < dof; ++k) { 7109 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7110 const PetscInt ind = indperm ? indperm[preind] : preind; 7111 7112 indices[ind] = off + k; 7113 } 7114 } else { 7115 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7116 for (k = 0; k < dof; ++k) { 7117 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7118 const PetscInt ind = indperm ? indperm[preind] : preind; 7119 7120 if ((cind < cdof) && (k == cdofs[cind])) { 7121 /* Insert check for returning constrained indices */ 7122 indices[ind] = -(off + k + 1); 7123 ++cind; 7124 } else { 7125 indices[ind] = off + k - (islocal ? 0 : cind); 7126 } 7127 } 7128 } 7129 *loff += dof; 7130 PetscFunctionReturn(PETSC_SUCCESS); 7131 } 7132 7133 /* 7134 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7135 7136 Input Parameters: 7137 + section - a section (global or local) 7138 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7139 . point - point within section 7140 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7141 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7142 . setBC - identify constrained (boundary condition) points via involution. 7143 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7144 . permsoff - offset 7145 - indperm - index permutation 7146 7147 Output Parameter: 7148 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7149 . indices - array to hold indices (as defined by section) of each dof associated with point 7150 7151 Notes: 7152 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7153 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7154 in the local vector. 7155 7156 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7157 significant). It is invalid to call with a global section and setBC=true. 7158 7159 Developer Note: 7160 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7161 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7162 offset could be obtained from the section instead of passing it explicitly as we do now. 7163 7164 Example: 7165 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7166 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7167 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7168 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. 7169 7170 Level: developer 7171 */ 7172 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[]) 7173 { 7174 PetscInt numFields, foff, f; 7175 7176 PetscFunctionBegin; 7177 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7178 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7179 for (f = 0, foff = 0; f < numFields; ++f) { 7180 PetscInt fdof, cfdof; 7181 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7182 PetscInt cind = 0, b; 7183 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7184 7185 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7186 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7187 if (!cfdof || setBC) { 7188 for (b = 0; b < fdof; ++b) { 7189 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7190 const PetscInt ind = indperm ? indperm[preind] : preind; 7191 7192 indices[ind] = off + foff + b; 7193 } 7194 } else { 7195 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7196 for (b = 0; b < fdof; ++b) { 7197 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7198 const PetscInt ind = indperm ? indperm[preind] : preind; 7199 7200 if ((cind < cfdof) && (b == fcdofs[cind])) { 7201 indices[ind] = -(off + foff + b + 1); 7202 ++cind; 7203 } else { 7204 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7205 } 7206 } 7207 } 7208 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7209 foffs[f] += fdof; 7210 } 7211 PetscFunctionReturn(PETSC_SUCCESS); 7212 } 7213 7214 /* 7215 This version believes the globalSection offsets for each field, rather than just the point offset 7216 7217 . foffs - The offset into 'indices' for each field, since it is segregated by field 7218 7219 Notes: 7220 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7221 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7222 */ 7223 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7224 { 7225 PetscInt numFields, foff, f; 7226 7227 PetscFunctionBegin; 7228 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7229 for (f = 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 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7238 if (!cfdof) { 7239 for (b = 0; b < fdof; ++b) { 7240 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7241 const PetscInt ind = indperm ? indperm[preind] : preind; 7242 7243 indices[ind] = foff + b; 7244 } 7245 } else { 7246 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7247 for (b = 0; b < fdof; ++b) { 7248 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7249 const PetscInt ind = indperm ? indperm[preind] : preind; 7250 7251 if ((cind < cfdof) && (b == fcdofs[cind])) { 7252 indices[ind] = -(foff + b + 1); 7253 ++cind; 7254 } else { 7255 indices[ind] = foff + b - cind; 7256 } 7257 } 7258 } 7259 foffs[f] += fdof; 7260 } 7261 PetscFunctionReturn(PETSC_SUCCESS); 7262 } 7263 7264 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) 7265 { 7266 Mat cMat; 7267 PetscSection aSec, cSec; 7268 IS aIS; 7269 PetscInt aStart = -1, aEnd = -1; 7270 const PetscInt *anchors; 7271 PetscInt numFields, f, p, q, newP = 0; 7272 PetscInt newNumPoints = 0, newNumIndices = 0; 7273 PetscInt *newPoints, *indices, *newIndices; 7274 PetscInt maxAnchor, maxDof; 7275 PetscInt newOffsets[32]; 7276 PetscInt *pointMatOffsets[32]; 7277 PetscInt *newPointOffsets[32]; 7278 PetscScalar *pointMat[32]; 7279 PetscScalar *newValues = NULL, *tmpValues; 7280 PetscBool anyConstrained = PETSC_FALSE; 7281 7282 PetscFunctionBegin; 7283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7284 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7285 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7286 7287 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7288 /* if there are point-to-point constraints */ 7289 if (aSec) { 7290 PetscCall(PetscArrayzero(newOffsets, 32)); 7291 PetscCall(ISGetIndices(aIS, &anchors)); 7292 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7293 /* figure out how many points are going to be in the new element matrix 7294 * (we allow double counting, because it's all just going to be summed 7295 * into the global matrix anyway) */ 7296 for (p = 0; p < 2 * numPoints; p += 2) { 7297 PetscInt b = points[p]; 7298 PetscInt bDof = 0, bSecDof; 7299 7300 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7301 if (!bSecDof) continue; 7302 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7303 if (bDof) { 7304 /* this point is constrained */ 7305 /* it is going to be replaced by its anchors */ 7306 PetscInt bOff, q; 7307 7308 anyConstrained = PETSC_TRUE; 7309 newNumPoints += bDof; 7310 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7311 for (q = 0; q < bDof; q++) { 7312 PetscInt a = anchors[bOff + q]; 7313 PetscInt aDof; 7314 7315 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7316 newNumIndices += aDof; 7317 for (f = 0; f < numFields; ++f) { 7318 PetscInt fDof; 7319 7320 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7321 newOffsets[f + 1] += fDof; 7322 } 7323 } 7324 } else { 7325 /* this point is not constrained */ 7326 newNumPoints++; 7327 newNumIndices += bSecDof; 7328 for (f = 0; f < numFields; ++f) { 7329 PetscInt fDof; 7330 7331 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7332 newOffsets[f + 1] += fDof; 7333 } 7334 } 7335 } 7336 } 7337 if (!anyConstrained) { 7338 if (outNumPoints) *outNumPoints = 0; 7339 if (outNumIndices) *outNumIndices = 0; 7340 if (outPoints) *outPoints = NULL; 7341 if (outValues) *outValues = NULL; 7342 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7343 PetscFunctionReturn(PETSC_SUCCESS); 7344 } 7345 7346 if (outNumPoints) *outNumPoints = newNumPoints; 7347 if (outNumIndices) *outNumIndices = newNumIndices; 7348 7349 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7350 7351 if (!outPoints && !outValues) { 7352 if (offsets) { 7353 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7354 } 7355 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7356 PetscFunctionReturn(PETSC_SUCCESS); 7357 } 7358 7359 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7360 7361 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7362 7363 /* workspaces */ 7364 if (numFields) { 7365 for (f = 0; f < numFields; f++) { 7366 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7367 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7368 } 7369 } else { 7370 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7371 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7372 } 7373 7374 /* get workspaces for the point-to-point matrices */ 7375 if (numFields) { 7376 PetscInt totalOffset, totalMatOffset; 7377 7378 for (p = 0; p < numPoints; p++) { 7379 PetscInt b = points[2 * p]; 7380 PetscInt bDof = 0, bSecDof; 7381 7382 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7383 if (!bSecDof) { 7384 for (f = 0; f < numFields; f++) { 7385 newPointOffsets[f][p + 1] = 0; 7386 pointMatOffsets[f][p + 1] = 0; 7387 } 7388 continue; 7389 } 7390 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7391 if (bDof) { 7392 for (f = 0; f < numFields; f++) { 7393 PetscInt fDof, q, bOff, allFDof = 0; 7394 7395 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7396 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7397 for (q = 0; q < bDof; q++) { 7398 PetscInt a = anchors[bOff + q]; 7399 PetscInt aFDof; 7400 7401 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7402 allFDof += aFDof; 7403 } 7404 newPointOffsets[f][p + 1] = allFDof; 7405 pointMatOffsets[f][p + 1] = fDof * allFDof; 7406 } 7407 } else { 7408 for (f = 0; f < numFields; f++) { 7409 PetscInt fDof; 7410 7411 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7412 newPointOffsets[f][p + 1] = fDof; 7413 pointMatOffsets[f][p + 1] = 0; 7414 } 7415 } 7416 } 7417 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7418 newPointOffsets[f][0] = totalOffset; 7419 pointMatOffsets[f][0] = totalMatOffset; 7420 for (p = 0; p < numPoints; p++) { 7421 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7422 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7423 } 7424 totalOffset = newPointOffsets[f][numPoints]; 7425 totalMatOffset = pointMatOffsets[f][numPoints]; 7426 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7427 } 7428 } else { 7429 for (p = 0; p < numPoints; p++) { 7430 PetscInt b = points[2 * p]; 7431 PetscInt bDof = 0, bSecDof; 7432 7433 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7434 if (!bSecDof) { 7435 newPointOffsets[0][p + 1] = 0; 7436 pointMatOffsets[0][p + 1] = 0; 7437 continue; 7438 } 7439 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7440 if (bDof) { 7441 PetscInt bOff, q, allDof = 0; 7442 7443 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7444 for (q = 0; q < bDof; q++) { 7445 PetscInt a = anchors[bOff + q], aDof; 7446 7447 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7448 allDof += aDof; 7449 } 7450 newPointOffsets[0][p + 1] = allDof; 7451 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7452 } else { 7453 newPointOffsets[0][p + 1] = bSecDof; 7454 pointMatOffsets[0][p + 1] = 0; 7455 } 7456 } 7457 newPointOffsets[0][0] = 0; 7458 pointMatOffsets[0][0] = 0; 7459 for (p = 0; p < numPoints; p++) { 7460 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7461 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7462 } 7463 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7464 } 7465 7466 /* output arrays */ 7467 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7468 7469 /* get the point-to-point matrices; construct newPoints */ 7470 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7471 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7472 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7473 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7474 if (numFields) { 7475 for (p = 0, newP = 0; p < numPoints; p++) { 7476 PetscInt b = points[2 * p]; 7477 PetscInt o = points[2 * p + 1]; 7478 PetscInt bDof = 0, bSecDof; 7479 7480 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7481 if (!bSecDof) continue; 7482 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7483 if (bDof) { 7484 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7485 7486 fStart[0] = 0; 7487 fEnd[0] = 0; 7488 for (f = 0; f < numFields; f++) { 7489 PetscInt fDof; 7490 7491 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7492 fStart[f + 1] = fStart[f] + fDof; 7493 fEnd[f + 1] = fStart[f + 1]; 7494 } 7495 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7496 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7497 7498 fAnchorStart[0] = 0; 7499 fAnchorEnd[0] = 0; 7500 for (f = 0; f < numFields; f++) { 7501 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7502 7503 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7504 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7505 } 7506 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7507 for (q = 0; q < bDof; q++) { 7508 PetscInt a = anchors[bOff + q], aOff; 7509 7510 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7511 newPoints[2 * (newP + q)] = a; 7512 newPoints[2 * (newP + q) + 1] = 0; 7513 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7514 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7515 } 7516 newP += bDof; 7517 7518 if (outValues) { 7519 /* get the point-to-point submatrix */ 7520 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])); 7521 } 7522 } else { 7523 newPoints[2 * newP] = b; 7524 newPoints[2 * newP + 1] = o; 7525 newP++; 7526 } 7527 } 7528 } else { 7529 for (p = 0; p < numPoints; p++) { 7530 PetscInt b = points[2 * p]; 7531 PetscInt o = points[2 * p + 1]; 7532 PetscInt bDof = 0, bSecDof; 7533 7534 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7535 if (!bSecDof) continue; 7536 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7537 if (bDof) { 7538 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7539 7540 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7541 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7542 7543 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7544 for (q = 0; q < bDof; q++) { 7545 PetscInt a = anchors[bOff + q], aOff; 7546 7547 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7548 7549 newPoints[2 * (newP + q)] = a; 7550 newPoints[2 * (newP + q) + 1] = 0; 7551 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7552 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7553 } 7554 newP += bDof; 7555 7556 /* get the point-to-point submatrix */ 7557 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7558 } else { 7559 newPoints[2 * newP] = b; 7560 newPoints[2 * newP + 1] = o; 7561 newP++; 7562 } 7563 } 7564 } 7565 7566 if (outValues) { 7567 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7568 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7569 /* multiply constraints on the right */ 7570 if (numFields) { 7571 for (f = 0; f < numFields; f++) { 7572 PetscInt oldOff = offsets[f]; 7573 7574 for (p = 0; p < numPoints; p++) { 7575 PetscInt cStart = newPointOffsets[f][p]; 7576 PetscInt b = points[2 * p]; 7577 PetscInt c, r, k; 7578 PetscInt dof; 7579 7580 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7581 if (!dof) continue; 7582 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7583 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7584 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7585 7586 for (r = 0; r < numIndices; r++) { 7587 for (c = 0; c < nCols; c++) { 7588 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7589 } 7590 } 7591 } else { 7592 /* copy this column as is */ 7593 for (r = 0; r < numIndices; r++) { 7594 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7595 } 7596 } 7597 oldOff += dof; 7598 } 7599 } 7600 } else { 7601 PetscInt oldOff = 0; 7602 for (p = 0; p < numPoints; p++) { 7603 PetscInt cStart = newPointOffsets[0][p]; 7604 PetscInt b = points[2 * p]; 7605 PetscInt c, r, k; 7606 PetscInt dof; 7607 7608 PetscCall(PetscSectionGetDof(section, b, &dof)); 7609 if (!dof) continue; 7610 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7611 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7612 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7613 7614 for (r = 0; r < numIndices; r++) { 7615 for (c = 0; c < nCols; c++) { 7616 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7617 } 7618 } 7619 } else { 7620 /* copy this column as is */ 7621 for (r = 0; r < numIndices; r++) { 7622 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7623 } 7624 } 7625 oldOff += dof; 7626 } 7627 } 7628 7629 if (multiplyLeft) { 7630 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7631 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7632 /* multiply constraints transpose on the left */ 7633 if (numFields) { 7634 for (f = 0; f < numFields; f++) { 7635 PetscInt oldOff = offsets[f]; 7636 7637 for (p = 0; p < numPoints; p++) { 7638 PetscInt rStart = newPointOffsets[f][p]; 7639 PetscInt b = points[2 * p]; 7640 PetscInt c, r, k; 7641 PetscInt dof; 7642 7643 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7644 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7645 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7646 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7647 7648 for (r = 0; r < nRows; r++) { 7649 for (c = 0; c < newNumIndices; c++) { 7650 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7651 } 7652 } 7653 } else { 7654 /* copy this row as is */ 7655 for (r = 0; r < dof; r++) { 7656 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7657 } 7658 } 7659 oldOff += dof; 7660 } 7661 } 7662 } else { 7663 PetscInt oldOff = 0; 7664 7665 for (p = 0; p < numPoints; p++) { 7666 PetscInt rStart = newPointOffsets[0][p]; 7667 PetscInt b = points[2 * p]; 7668 PetscInt c, r, k; 7669 PetscInt dof; 7670 7671 PetscCall(PetscSectionGetDof(section, b, &dof)); 7672 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7673 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7674 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7675 7676 for (r = 0; r < nRows; r++) { 7677 for (c = 0; c < newNumIndices; c++) { 7678 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7679 } 7680 } 7681 } else { 7682 /* copy this row as is */ 7683 for (r = 0; r < dof; r++) { 7684 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7685 } 7686 } 7687 oldOff += dof; 7688 } 7689 } 7690 7691 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7692 } else { 7693 newValues = tmpValues; 7694 } 7695 } 7696 7697 /* clean up */ 7698 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7699 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7700 7701 if (numFields) { 7702 for (f = 0; f < numFields; f++) { 7703 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7704 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7705 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7706 } 7707 } else { 7708 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7709 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7710 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7711 } 7712 PetscCall(ISRestoreIndices(aIS, &anchors)); 7713 7714 /* output */ 7715 if (outPoints) { 7716 *outPoints = newPoints; 7717 } else { 7718 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7719 } 7720 if (outValues) *outValues = newValues; 7721 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7722 PetscFunctionReturn(PETSC_SUCCESS); 7723 } 7724 7725 /*@C 7726 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7727 7728 Not collective 7729 7730 Input Parameters: 7731 + dm - The `DM` 7732 . section - The `PetscSection` describing the points (a local section) 7733 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7734 . point - The point defining the closure 7735 - useClPerm - Use the closure point permutation if available 7736 7737 Output Parameters: 7738 + numIndices - The number of dof indices in the closure of point with the input sections 7739 . indices - The dof indices 7740 . outOffsets - Array to write the field offsets into, or `NULL` 7741 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7742 7743 Level: advanced 7744 7745 Notes: 7746 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7747 7748 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7749 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7750 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7751 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7752 indices (with the above semantics) are implied. 7753 7754 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7755 `PetscSection`, `DMGetGlobalSection()` 7756 @*/ 7757 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7758 { 7759 /* Closure ordering */ 7760 PetscSection clSection; 7761 IS clPoints; 7762 const PetscInt *clp; 7763 PetscInt *points; 7764 const PetscInt *clperm = NULL; 7765 /* Dof permutation and sign flips */ 7766 const PetscInt **perms[32] = {NULL}; 7767 const PetscScalar **flips[32] = {NULL}; 7768 PetscScalar *valCopy = NULL; 7769 /* Hanging node constraints */ 7770 PetscInt *pointsC = NULL; 7771 PetscScalar *valuesC = NULL; 7772 PetscInt NclC, NiC; 7773 7774 PetscInt *idx; 7775 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7776 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7777 7778 PetscFunctionBeginHot; 7779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7780 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7781 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7782 if (numIndices) PetscAssertPointer(numIndices, 6); 7783 if (indices) PetscAssertPointer(indices, 7); 7784 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7785 if (values) PetscAssertPointer(values, 9); 7786 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7787 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7788 PetscCall(PetscArrayzero(offsets, 32)); 7789 /* 1) Get points in closure */ 7790 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7791 if (useClPerm) { 7792 PetscInt depth, clsize; 7793 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7794 for (clsize = 0, p = 0; p < Ncl; p++) { 7795 PetscInt dof; 7796 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7797 clsize += dof; 7798 } 7799 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7800 } 7801 /* 2) Get number of indices on these points and field offsets from section */ 7802 for (p = 0; p < Ncl * 2; p += 2) { 7803 PetscInt dof, fdof; 7804 7805 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7806 for (f = 0; f < Nf; ++f) { 7807 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7808 offsets[f + 1] += fdof; 7809 } 7810 Ni += dof; 7811 } 7812 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7813 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7814 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7815 for (f = 0; f < PetscMax(1, Nf); ++f) { 7816 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7817 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7818 /* may need to apply sign changes to the element matrix */ 7819 if (values && flips[f]) { 7820 PetscInt foffset = offsets[f]; 7821 7822 for (p = 0; p < Ncl; ++p) { 7823 PetscInt pnt = points[2 * p], fdof; 7824 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7825 7826 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7827 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7828 if (flip) { 7829 PetscInt i, j, k; 7830 7831 if (!valCopy) { 7832 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7833 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7834 *values = valCopy; 7835 } 7836 for (i = 0; i < fdof; ++i) { 7837 PetscScalar fval = flip[i]; 7838 7839 for (k = 0; k < Ni; ++k) { 7840 valCopy[Ni * (foffset + i) + k] *= fval; 7841 valCopy[Ni * k + (foffset + i)] *= fval; 7842 } 7843 } 7844 } 7845 foffset += fdof; 7846 } 7847 } 7848 } 7849 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7850 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7851 if (NclC) { 7852 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7853 for (f = 0; f < PetscMax(1, Nf); ++f) { 7854 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7855 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7856 } 7857 for (f = 0; f < PetscMax(1, Nf); ++f) { 7858 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7859 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7860 } 7861 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7862 Ncl = NclC; 7863 Ni = NiC; 7864 points = pointsC; 7865 if (values) *values = valuesC; 7866 } 7867 /* 5) Calculate indices */ 7868 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7869 if (Nf) { 7870 PetscInt idxOff; 7871 PetscBool useFieldOffsets; 7872 7873 if (outOffsets) { 7874 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7875 } 7876 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7877 if (useFieldOffsets) { 7878 for (p = 0; p < Ncl; ++p) { 7879 const PetscInt pnt = points[p * 2]; 7880 7881 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7882 } 7883 } else { 7884 for (p = 0; p < Ncl; ++p) { 7885 const PetscInt pnt = points[p * 2]; 7886 7887 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7888 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7889 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7890 * global section. */ 7891 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7892 } 7893 } 7894 } else { 7895 PetscInt off = 0, idxOff; 7896 7897 for (p = 0; p < Ncl; ++p) { 7898 const PetscInt pnt = points[p * 2]; 7899 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7900 7901 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7902 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7903 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7904 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7905 } 7906 } 7907 /* 6) Cleanup */ 7908 for (f = 0; f < PetscMax(1, Nf); ++f) { 7909 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7910 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7911 } 7912 if (NclC) { 7913 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7914 } else { 7915 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7916 } 7917 7918 if (numIndices) *numIndices = Ni; 7919 if (indices) *indices = idx; 7920 PetscFunctionReturn(PETSC_SUCCESS); 7921 } 7922 7923 /*@C 7924 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7925 7926 Not collective 7927 7928 Input Parameters: 7929 + dm - The `DM` 7930 . section - The `PetscSection` describing the points (a local section) 7931 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7932 . point - The point defining the closure 7933 - useClPerm - Use the closure point permutation if available 7934 7935 Output Parameters: 7936 + numIndices - The number of dof indices in the closure of point with the input sections 7937 . indices - The dof indices 7938 . outOffsets - Array to write the field offsets into, or `NULL` 7939 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7940 7941 Level: advanced 7942 7943 Notes: 7944 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7945 7946 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7947 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7948 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7949 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7950 indices (with the above semantics) are implied. 7951 7952 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7953 @*/ 7954 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7955 { 7956 PetscFunctionBegin; 7957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7958 PetscAssertPointer(indices, 7); 7959 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7960 PetscFunctionReturn(PETSC_SUCCESS); 7961 } 7962 7963 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7964 { 7965 DM_Plex *mesh = (DM_Plex *)dm->data; 7966 PetscInt *indices; 7967 PetscInt numIndices; 7968 const PetscScalar *valuesOrig = values; 7969 PetscErrorCode ierr; 7970 7971 PetscFunctionBegin; 7972 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7973 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7974 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7975 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7976 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7977 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 7978 7979 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7980 7981 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7982 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7983 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7984 if (ierr) { 7985 PetscMPIInt rank; 7986 7987 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7988 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7989 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7990 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7991 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7992 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7993 } 7994 if (mesh->printFEM > 1) { 7995 PetscInt i; 7996 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7997 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7998 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7999 } 8000 8001 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8002 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8003 PetscFunctionReturn(PETSC_SUCCESS); 8004 } 8005 8006 /*@C 8007 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8008 8009 Not collective 8010 8011 Input Parameters: 8012 + dm - The `DM` 8013 . section - The section describing the layout in `v`, or `NULL` to use the default section 8014 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8015 . A - The matrix 8016 . point - The point in the `DM` 8017 . values - The array of values 8018 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8019 8020 Level: intermediate 8021 8022 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8023 @*/ 8024 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8025 { 8026 PetscFunctionBegin; 8027 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8028 PetscFunctionReturn(PETSC_SUCCESS); 8029 } 8030 8031 /*@C 8032 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8033 8034 Not collective 8035 8036 Input Parameters: 8037 + dmRow - The `DM` for the row fields 8038 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8039 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8040 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8041 . dmCol - The `DM` for the column fields 8042 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8043 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8044 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8045 . A - The matrix 8046 . point - The point in the `DM` 8047 . values - The array of values 8048 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8049 8050 Level: intermediate 8051 8052 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8053 @*/ 8054 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) 8055 { 8056 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8057 PetscInt *indicesRow, *indicesCol; 8058 PetscInt numIndicesRow, numIndicesCol; 8059 const PetscScalar *valuesOrig = values; 8060 PetscErrorCode ierr; 8061 8062 PetscFunctionBegin; 8063 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8064 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8065 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8066 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8067 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8068 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8069 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8070 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8071 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8072 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8073 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8074 8075 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8076 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8077 8078 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8079 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8080 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8081 if (ierr) { 8082 PetscMPIInt rank; 8083 8084 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8085 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8086 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8087 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8088 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8089 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8090 } 8091 8092 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8093 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8094 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8095 PetscFunctionReturn(PETSC_SUCCESS); 8096 } 8097 8098 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8099 { 8100 DM_Plex *mesh = (DM_Plex *)dmf->data; 8101 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8102 PetscInt *cpoints = NULL; 8103 PetscInt *findices, *cindices; 8104 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8105 PetscInt foffsets[32], coffsets[32]; 8106 DMPolytopeType ct; 8107 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8108 PetscErrorCode ierr; 8109 8110 PetscFunctionBegin; 8111 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8112 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8113 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8114 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8115 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8116 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8117 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8118 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8119 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8120 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8121 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8122 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8123 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8124 PetscCall(PetscArrayzero(foffsets, 32)); 8125 PetscCall(PetscArrayzero(coffsets, 32)); 8126 /* Column indices */ 8127 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8128 maxFPoints = numCPoints; 8129 /* Compress out points not in the section */ 8130 /* TODO: Squeeze out points with 0 dof as well */ 8131 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8132 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8133 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8134 cpoints[q * 2] = cpoints[p]; 8135 cpoints[q * 2 + 1] = cpoints[p + 1]; 8136 ++q; 8137 } 8138 } 8139 numCPoints = q; 8140 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8141 PetscInt fdof; 8142 8143 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8144 if (!dof) continue; 8145 for (f = 0; f < numFields; ++f) { 8146 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8147 coffsets[f + 1] += fdof; 8148 } 8149 numCIndices += dof; 8150 } 8151 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8152 /* Row indices */ 8153 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8154 { 8155 DMPlexTransform tr; 8156 DMPolytopeType *rct; 8157 PetscInt *rsize, *rcone, *rornt, Nt; 8158 8159 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8160 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8161 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8162 numSubcells = rsize[Nt - 1]; 8163 PetscCall(DMPlexTransformDestroy(&tr)); 8164 } 8165 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8166 for (r = 0, q = 0; r < numSubcells; ++r) { 8167 /* TODO Map from coarse to fine cells */ 8168 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8169 /* Compress out points not in the section */ 8170 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8171 for (p = 0; p < numFPoints * 2; p += 2) { 8172 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8173 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8174 if (!dof) continue; 8175 for (s = 0; s < q; ++s) 8176 if (fpoints[p] == ftotpoints[s * 2]) break; 8177 if (s < q) continue; 8178 ftotpoints[q * 2] = fpoints[p]; 8179 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8180 ++q; 8181 } 8182 } 8183 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8184 } 8185 numFPoints = q; 8186 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8187 PetscInt fdof; 8188 8189 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8190 if (!dof) continue; 8191 for (f = 0; f < numFields; ++f) { 8192 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8193 foffsets[f + 1] += fdof; 8194 } 8195 numFIndices += dof; 8196 } 8197 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8198 8199 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8200 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8201 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8202 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8203 if (numFields) { 8204 const PetscInt **permsF[32] = {NULL}; 8205 const PetscInt **permsC[32] = {NULL}; 8206 8207 for (f = 0; f < numFields; f++) { 8208 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8209 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8210 } 8211 for (p = 0; p < numFPoints; p++) { 8212 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8213 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8214 } 8215 for (p = 0; p < numCPoints; p++) { 8216 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8217 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8218 } 8219 for (f = 0; f < numFields; f++) { 8220 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8221 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8222 } 8223 } else { 8224 const PetscInt **permsF = NULL; 8225 const PetscInt **permsC = NULL; 8226 8227 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8228 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8229 for (p = 0, off = 0; p < numFPoints; p++) { 8230 const PetscInt *perm = permsF ? permsF[p] : NULL; 8231 8232 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8233 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8234 } 8235 for (p = 0, off = 0; p < numCPoints; p++) { 8236 const PetscInt *perm = permsC ? permsC[p] : NULL; 8237 8238 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8239 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8240 } 8241 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8242 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8243 } 8244 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8245 /* TODO: flips */ 8246 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8247 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8248 if (ierr) { 8249 PetscMPIInt rank; 8250 8251 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8252 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8253 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8254 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8255 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8256 } 8257 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8258 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8259 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8260 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8261 PetscFunctionReturn(PETSC_SUCCESS); 8262 } 8263 8264 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8265 { 8266 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8267 PetscInt *cpoints = NULL; 8268 PetscInt foffsets[32], coffsets[32]; 8269 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8270 DMPolytopeType ct; 8271 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8272 8273 PetscFunctionBegin; 8274 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8275 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8276 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8277 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8278 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8279 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8280 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8281 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8282 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8283 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8284 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8285 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8286 PetscCall(PetscArrayzero(foffsets, 32)); 8287 PetscCall(PetscArrayzero(coffsets, 32)); 8288 /* Column indices */ 8289 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8290 maxFPoints = numCPoints; 8291 /* Compress out points not in the section */ 8292 /* TODO: Squeeze out points with 0 dof as well */ 8293 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8294 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8295 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8296 cpoints[q * 2] = cpoints[p]; 8297 cpoints[q * 2 + 1] = cpoints[p + 1]; 8298 ++q; 8299 } 8300 } 8301 numCPoints = q; 8302 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8303 PetscInt fdof; 8304 8305 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8306 if (!dof) continue; 8307 for (f = 0; f < numFields; ++f) { 8308 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8309 coffsets[f + 1] += fdof; 8310 } 8311 numCIndices += dof; 8312 } 8313 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8314 /* Row indices */ 8315 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8316 { 8317 DMPlexTransform tr; 8318 DMPolytopeType *rct; 8319 PetscInt *rsize, *rcone, *rornt, Nt; 8320 8321 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8322 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8323 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8324 numSubcells = rsize[Nt - 1]; 8325 PetscCall(DMPlexTransformDestroy(&tr)); 8326 } 8327 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8328 for (r = 0, q = 0; r < numSubcells; ++r) { 8329 /* TODO Map from coarse to fine cells */ 8330 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8331 /* Compress out points not in the section */ 8332 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8333 for (p = 0; p < numFPoints * 2; p += 2) { 8334 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8335 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8336 if (!dof) continue; 8337 for (s = 0; s < q; ++s) 8338 if (fpoints[p] == ftotpoints[s * 2]) break; 8339 if (s < q) continue; 8340 ftotpoints[q * 2] = fpoints[p]; 8341 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8342 ++q; 8343 } 8344 } 8345 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8346 } 8347 numFPoints = q; 8348 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8349 PetscInt fdof; 8350 8351 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8352 if (!dof) continue; 8353 for (f = 0; f < numFields; ++f) { 8354 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8355 foffsets[f + 1] += fdof; 8356 } 8357 numFIndices += dof; 8358 } 8359 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8360 8361 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8362 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8363 if (numFields) { 8364 const PetscInt **permsF[32] = {NULL}; 8365 const PetscInt **permsC[32] = {NULL}; 8366 8367 for (f = 0; f < numFields; f++) { 8368 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8369 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8370 } 8371 for (p = 0; p < numFPoints; p++) { 8372 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8373 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8374 } 8375 for (p = 0; p < numCPoints; p++) { 8376 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8377 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8378 } 8379 for (f = 0; f < numFields; f++) { 8380 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8381 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8382 } 8383 } else { 8384 const PetscInt **permsF = NULL; 8385 const PetscInt **permsC = NULL; 8386 8387 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8388 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8389 for (p = 0, off = 0; p < numFPoints; p++) { 8390 const PetscInt *perm = permsF ? permsF[p] : NULL; 8391 8392 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8393 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8394 } 8395 for (p = 0, off = 0; p < numCPoints; p++) { 8396 const PetscInt *perm = permsC ? permsC[p] : NULL; 8397 8398 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8399 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8400 } 8401 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8402 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8403 } 8404 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8405 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8406 PetscFunctionReturn(PETSC_SUCCESS); 8407 } 8408 8409 /*@C 8410 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8411 8412 Input Parameter: 8413 . dm - The `DMPLEX` object 8414 8415 Output Parameter: 8416 . cellHeight - The height of a cell 8417 8418 Level: developer 8419 8420 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8421 @*/ 8422 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8423 { 8424 DM_Plex *mesh = (DM_Plex *)dm->data; 8425 8426 PetscFunctionBegin; 8427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8428 PetscAssertPointer(cellHeight, 2); 8429 *cellHeight = mesh->vtkCellHeight; 8430 PetscFunctionReturn(PETSC_SUCCESS); 8431 } 8432 8433 /*@C 8434 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8435 8436 Input Parameters: 8437 + dm - The `DMPLEX` object 8438 - cellHeight - The height of a cell 8439 8440 Level: developer 8441 8442 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8443 @*/ 8444 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8445 { 8446 DM_Plex *mesh = (DM_Plex *)dm->data; 8447 8448 PetscFunctionBegin; 8449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8450 mesh->vtkCellHeight = cellHeight; 8451 PetscFunctionReturn(PETSC_SUCCESS); 8452 } 8453 8454 /*@ 8455 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8456 8457 Input Parameters: 8458 + dm - The `DMPLEX` object 8459 - ct - The `DMPolytopeType` of the cell 8460 8461 Output Parameters: 8462 + start - The first cell of this type, or `NULL` 8463 - end - The upper bound on this celltype, or `NULL` 8464 8465 Level: advanced 8466 8467 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8468 @*/ 8469 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8470 { 8471 DM_Plex *mesh = (DM_Plex *)dm->data; 8472 DMLabel label; 8473 PetscInt pStart, pEnd; 8474 8475 PetscFunctionBegin; 8476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8477 if (start) { 8478 PetscAssertPointer(start, 3); 8479 *start = 0; 8480 } 8481 if (end) { 8482 PetscAssertPointer(end, 4); 8483 *end = 0; 8484 } 8485 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8486 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8487 if (mesh->tr) { 8488 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8489 } else { 8490 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8491 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8492 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8493 } 8494 PetscFunctionReturn(PETSC_SUCCESS); 8495 } 8496 8497 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8498 { 8499 PetscSection section, globalSection; 8500 PetscInt *numbers, p; 8501 8502 PetscFunctionBegin; 8503 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8504 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8505 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8506 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8507 PetscCall(PetscSectionSetUp(section)); 8508 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8509 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8510 for (p = pStart; p < pEnd; ++p) { 8511 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8512 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8513 else numbers[p - pStart] += shift; 8514 } 8515 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8516 if (globalSize) { 8517 PetscLayout layout; 8518 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8519 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8520 PetscCall(PetscLayoutDestroy(&layout)); 8521 } 8522 PetscCall(PetscSectionDestroy(§ion)); 8523 PetscCall(PetscSectionDestroy(&globalSection)); 8524 PetscFunctionReturn(PETSC_SUCCESS); 8525 } 8526 8527 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8528 { 8529 PetscInt cellHeight, cStart, cEnd; 8530 8531 PetscFunctionBegin; 8532 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8533 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8534 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8535 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8536 PetscFunctionReturn(PETSC_SUCCESS); 8537 } 8538 8539 /*@ 8540 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8541 8542 Input Parameter: 8543 . dm - The `DMPLEX` object 8544 8545 Output Parameter: 8546 . globalCellNumbers - Global cell numbers for all cells on this process 8547 8548 Level: developer 8549 8550 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8551 @*/ 8552 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8553 { 8554 DM_Plex *mesh = (DM_Plex *)dm->data; 8555 8556 PetscFunctionBegin; 8557 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8558 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8559 *globalCellNumbers = mesh->globalCellNumbers; 8560 PetscFunctionReturn(PETSC_SUCCESS); 8561 } 8562 8563 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8564 { 8565 PetscInt vStart, vEnd; 8566 8567 PetscFunctionBegin; 8568 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8569 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8570 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8571 PetscFunctionReturn(PETSC_SUCCESS); 8572 } 8573 8574 /*@ 8575 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8576 8577 Input Parameter: 8578 . dm - The `DMPLEX` object 8579 8580 Output Parameter: 8581 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8582 8583 Level: developer 8584 8585 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8586 @*/ 8587 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8588 { 8589 DM_Plex *mesh = (DM_Plex *)dm->data; 8590 8591 PetscFunctionBegin; 8592 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8593 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8594 *globalVertexNumbers = mesh->globalVertexNumbers; 8595 PetscFunctionReturn(PETSC_SUCCESS); 8596 } 8597 8598 /*@ 8599 DMPlexCreatePointNumbering - Create a global numbering for all points. 8600 8601 Collective 8602 8603 Input Parameter: 8604 . dm - The `DMPLEX` object 8605 8606 Output Parameter: 8607 . globalPointNumbers - Global numbers for all points on this process 8608 8609 Level: developer 8610 8611 Notes: 8612 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8613 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8614 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8615 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8616 8617 The partitioned mesh is 8618 ``` 8619 (2)--0--(3)--1--(4) (1)--0--(2) 8620 ``` 8621 and its global numbering is 8622 ``` 8623 (3)--0--(4)--1--(5)--2--(6) 8624 ``` 8625 Then the global numbering is provided as 8626 ``` 8627 [0] Number of indices in set 5 8628 [0] 0 0 8629 [0] 1 1 8630 [0] 2 3 8631 [0] 3 4 8632 [0] 4 -6 8633 [1] Number of indices in set 3 8634 [1] 0 2 8635 [1] 1 5 8636 [1] 2 6 8637 ``` 8638 8639 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8640 @*/ 8641 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8642 { 8643 IS nums[4]; 8644 PetscInt depths[4], gdepths[4], starts[4]; 8645 PetscInt depth, d, shift = 0; 8646 PetscBool empty = PETSC_FALSE; 8647 8648 PetscFunctionBegin; 8649 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8650 PetscCall(DMPlexGetDepth(dm, &depth)); 8651 // For unstratified meshes use dim instead of depth 8652 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8653 // If any stratum is empty, we must mark all empty 8654 for (d = 0; d <= depth; ++d) { 8655 PetscInt end; 8656 8657 depths[d] = depth - d; 8658 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8659 if (!(starts[d] - end)) empty = PETSC_TRUE; 8660 } 8661 if (empty) 8662 for (d = 0; d <= depth; ++d) { 8663 depths[d] = -1; 8664 starts[d] = -1; 8665 } 8666 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8667 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8668 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]); 8669 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8670 for (d = 0; d <= depth; ++d) { 8671 PetscInt pStart, pEnd, gsize; 8672 8673 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8674 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8675 shift += gsize; 8676 } 8677 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8678 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8679 PetscFunctionReturn(PETSC_SUCCESS); 8680 } 8681 8682 /*@ 8683 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8684 8685 Input Parameter: 8686 . dm - The `DMPLEX` object 8687 8688 Output Parameter: 8689 . ranks - The rank field 8690 8691 Options Database Key: 8692 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8693 8694 Level: intermediate 8695 8696 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8697 @*/ 8698 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8699 { 8700 DM rdm; 8701 PetscFE fe; 8702 PetscScalar *r; 8703 PetscMPIInt rank; 8704 DMPolytopeType ct; 8705 PetscInt dim, cStart, cEnd, c; 8706 PetscBool simplex; 8707 8708 PetscFunctionBeginUser; 8709 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8710 PetscAssertPointer(ranks, 2); 8711 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8712 PetscCall(DMClone(dm, &rdm)); 8713 PetscCall(DMGetDimension(rdm, &dim)); 8714 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8715 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8716 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8717 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8718 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8719 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8720 PetscCall(PetscFEDestroy(&fe)); 8721 PetscCall(DMCreateDS(rdm)); 8722 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8723 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8724 PetscCall(VecGetArray(*ranks, &r)); 8725 for (c = cStart; c < cEnd; ++c) { 8726 PetscScalar *lr; 8727 8728 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8729 if (lr) *lr = rank; 8730 } 8731 PetscCall(VecRestoreArray(*ranks, &r)); 8732 PetscCall(DMDestroy(&rdm)); 8733 PetscFunctionReturn(PETSC_SUCCESS); 8734 } 8735 8736 /*@ 8737 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8738 8739 Input Parameters: 8740 + dm - The `DMPLEX` 8741 - label - The `DMLabel` 8742 8743 Output Parameter: 8744 . val - The label value field 8745 8746 Options Database Key: 8747 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8748 8749 Level: intermediate 8750 8751 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8752 @*/ 8753 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8754 { 8755 DM rdm; 8756 PetscFE fe; 8757 PetscScalar *v; 8758 PetscInt dim, cStart, cEnd, c; 8759 8760 PetscFunctionBeginUser; 8761 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8762 PetscAssertPointer(label, 2); 8763 PetscAssertPointer(val, 3); 8764 PetscCall(DMClone(dm, &rdm)); 8765 PetscCall(DMGetDimension(rdm, &dim)); 8766 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8767 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8768 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8769 PetscCall(PetscFEDestroy(&fe)); 8770 PetscCall(DMCreateDS(rdm)); 8771 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8772 PetscCall(DMCreateGlobalVector(rdm, val)); 8773 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8774 PetscCall(VecGetArray(*val, &v)); 8775 for (c = cStart; c < cEnd; ++c) { 8776 PetscScalar *lv; 8777 PetscInt cval; 8778 8779 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8780 PetscCall(DMLabelGetValue(label, c, &cval)); 8781 *lv = cval; 8782 } 8783 PetscCall(VecRestoreArray(*val, &v)); 8784 PetscCall(DMDestroy(&rdm)); 8785 PetscFunctionReturn(PETSC_SUCCESS); 8786 } 8787 8788 /*@ 8789 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8790 8791 Input Parameter: 8792 . dm - The `DMPLEX` object 8793 8794 Level: developer 8795 8796 Notes: 8797 This is a useful diagnostic when creating meshes programmatically. 8798 8799 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8800 8801 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8802 @*/ 8803 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8804 { 8805 PetscSection coneSection, supportSection; 8806 const PetscInt *cone, *support; 8807 PetscInt coneSize, c, supportSize, s; 8808 PetscInt pStart, pEnd, p, pp, csize, ssize; 8809 PetscBool storagecheck = PETSC_TRUE; 8810 8811 PetscFunctionBegin; 8812 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8813 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8814 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8815 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8816 /* Check that point p is found in the support of its cone points, and vice versa */ 8817 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8818 for (p = pStart; p < pEnd; ++p) { 8819 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8820 PetscCall(DMPlexGetCone(dm, p, &cone)); 8821 for (c = 0; c < coneSize; ++c) { 8822 PetscBool dup = PETSC_FALSE; 8823 PetscInt d; 8824 for (d = c - 1; d >= 0; --d) { 8825 if (cone[c] == cone[d]) { 8826 dup = PETSC_TRUE; 8827 break; 8828 } 8829 } 8830 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8831 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8832 for (s = 0; s < supportSize; ++s) { 8833 if (support[s] == p) break; 8834 } 8835 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8836 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8837 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8838 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8839 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8840 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8841 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8842 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]); 8843 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8844 } 8845 } 8846 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8847 if (p != pp) { 8848 storagecheck = PETSC_FALSE; 8849 continue; 8850 } 8851 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8852 PetscCall(DMPlexGetSupport(dm, p, &support)); 8853 for (s = 0; s < supportSize; ++s) { 8854 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8855 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8856 for (c = 0; c < coneSize; ++c) { 8857 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8858 if (cone[c] != pp) { 8859 c = 0; 8860 break; 8861 } 8862 if (cone[c] == p) break; 8863 } 8864 if (c >= coneSize) { 8865 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8866 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8867 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8868 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8869 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8870 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8871 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8872 } 8873 } 8874 } 8875 if (storagecheck) { 8876 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8877 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8878 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8879 } 8880 PetscFunctionReturn(PETSC_SUCCESS); 8881 } 8882 8883 /* 8884 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. 8885 */ 8886 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8887 { 8888 DMPolytopeType cct; 8889 PetscInt ptpoints[4]; 8890 const PetscInt *cone, *ccone, *ptcone; 8891 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8892 8893 PetscFunctionBegin; 8894 *unsplit = 0; 8895 switch (ct) { 8896 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8897 ptpoints[npt++] = c; 8898 break; 8899 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8900 PetscCall(DMPlexGetCone(dm, c, &cone)); 8901 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8902 for (cp = 0; cp < coneSize; ++cp) { 8903 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8904 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8905 } 8906 break; 8907 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8908 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8909 PetscCall(DMPlexGetCone(dm, c, &cone)); 8910 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8911 for (cp = 0; cp < coneSize; ++cp) { 8912 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8913 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8914 for (ccp = 0; ccp < cconeSize; ++ccp) { 8915 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8916 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8917 PetscInt p; 8918 for (p = 0; p < npt; ++p) 8919 if (ptpoints[p] == ccone[ccp]) break; 8920 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8921 } 8922 } 8923 } 8924 break; 8925 default: 8926 break; 8927 } 8928 for (pt = 0; pt < npt; ++pt) { 8929 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8930 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8931 } 8932 PetscFunctionReturn(PETSC_SUCCESS); 8933 } 8934 8935 /*@ 8936 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8937 8938 Input Parameters: 8939 + dm - The `DMPLEX` object 8940 - cellHeight - Normally 0 8941 8942 Level: developer 8943 8944 Notes: 8945 This is a useful diagnostic when creating meshes programmatically. 8946 Currently applicable only to homogeneous simplex or tensor meshes. 8947 8948 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8949 8950 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8951 @*/ 8952 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8953 { 8954 DMPlexInterpolatedFlag interp; 8955 DMPolytopeType ct; 8956 PetscInt vStart, vEnd, cStart, cEnd, c; 8957 8958 PetscFunctionBegin; 8959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8960 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8961 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8962 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8963 for (c = cStart; c < cEnd; ++c) { 8964 PetscInt *closure = NULL; 8965 PetscInt coneSize, closureSize, cl, Nv = 0; 8966 8967 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8968 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8969 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8970 if (interp == DMPLEX_INTERPOLATED_FULL) { 8971 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8972 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)); 8973 } 8974 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8975 for (cl = 0; cl < closureSize * 2; cl += 2) { 8976 const PetscInt p = closure[cl]; 8977 if ((p >= vStart) && (p < vEnd)) ++Nv; 8978 } 8979 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8980 /* Special Case: Tensor faces with identified vertices */ 8981 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8982 PetscInt unsplit; 8983 8984 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8985 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8986 } 8987 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)); 8988 } 8989 PetscFunctionReturn(PETSC_SUCCESS); 8990 } 8991 8992 /*@ 8993 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8994 8995 Collective 8996 8997 Input Parameters: 8998 + dm - The `DMPLEX` object 8999 - cellHeight - Normally 0 9000 9001 Level: developer 9002 9003 Notes: 9004 This is a useful diagnostic when creating meshes programmatically. 9005 This routine is only relevant for meshes that are fully interpolated across all ranks. 9006 It will error out if a partially interpolated mesh is given on some rank. 9007 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9008 9009 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9010 9011 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9012 @*/ 9013 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9014 { 9015 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9016 DMPlexInterpolatedFlag interpEnum; 9017 9018 PetscFunctionBegin; 9019 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9020 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9021 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9022 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9023 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9024 PetscFunctionReturn(PETSC_SUCCESS); 9025 } 9026 9027 PetscCall(DMGetDimension(dm, &dim)); 9028 PetscCall(DMPlexGetDepth(dm, &depth)); 9029 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9030 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9031 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9032 for (c = cStart; c < cEnd; ++c) { 9033 const PetscInt *cone, *ornt, *faceSizes, *faces; 9034 const DMPolytopeType *faceTypes; 9035 DMPolytopeType ct; 9036 PetscInt numFaces, coneSize, f; 9037 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9038 9039 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9040 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9041 if (unsplit) continue; 9042 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9043 PetscCall(DMPlexGetCone(dm, c, &cone)); 9044 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9045 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9046 for (cl = 0; cl < closureSize * 2; cl += 2) { 9047 const PetscInt p = closure[cl]; 9048 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9049 } 9050 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9051 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); 9052 for (f = 0; f < numFaces; ++f) { 9053 DMPolytopeType fct; 9054 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9055 9056 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9057 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9058 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9059 const PetscInt p = fclosure[cl]; 9060 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9061 } 9062 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]); 9063 for (v = 0; v < fnumCorners; ++v) { 9064 if (fclosure[v] != faces[fOff + v]) { 9065 PetscInt v1; 9066 9067 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9068 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9069 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9070 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9071 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9072 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]); 9073 } 9074 } 9075 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9076 fOff += faceSizes[f]; 9077 } 9078 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9079 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9080 } 9081 } 9082 PetscFunctionReturn(PETSC_SUCCESS); 9083 } 9084 9085 /*@ 9086 DMPlexCheckGeometry - Check the geometry of mesh cells 9087 9088 Input Parameter: 9089 . dm - The `DMPLEX` object 9090 9091 Level: developer 9092 9093 Notes: 9094 This is a useful diagnostic when creating meshes programmatically. 9095 9096 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9097 9098 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9099 @*/ 9100 PetscErrorCode DMPlexCheckGeometry(DM dm) 9101 { 9102 Vec coordinates; 9103 PetscReal detJ, J[9], refVol = 1.0; 9104 PetscReal vol; 9105 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9106 9107 PetscFunctionBegin; 9108 PetscCall(DMGetDimension(dm, &dim)); 9109 PetscCall(DMGetCoordinateDim(dm, &dE)); 9110 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9111 PetscCall(DMPlexGetDepth(dm, &depth)); 9112 for (d = 0; d < dim; ++d) refVol *= 2.0; 9113 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9114 /* Make sure local coordinates are created, because that step is collective */ 9115 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9116 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9117 for (c = cStart; c < cEnd; ++c) { 9118 DMPolytopeType ct; 9119 PetscInt unsplit; 9120 PetscBool ignoreZeroVol = PETSC_FALSE; 9121 9122 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9123 switch (ct) { 9124 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9125 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9126 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9127 ignoreZeroVol = PETSC_TRUE; 9128 break; 9129 default: 9130 break; 9131 } 9132 switch (ct) { 9133 case DM_POLYTOPE_TRI_PRISM: 9134 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9135 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9136 case DM_POLYTOPE_PYRAMID: 9137 continue; 9138 default: 9139 break; 9140 } 9141 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9142 if (unsplit) continue; 9143 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9144 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); 9145 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9146 /* This should work with periodicity since DG coordinates should be used */ 9147 if (depth > 1) { 9148 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9149 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); 9150 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9151 } 9152 } 9153 PetscFunctionReturn(PETSC_SUCCESS); 9154 } 9155 9156 /*@ 9157 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9158 9159 Collective 9160 9161 Input Parameters: 9162 + dm - The `DMPLEX` object 9163 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9164 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9165 9166 Level: developer 9167 9168 Notes: 9169 This is mainly intended for debugging/testing purposes. 9170 9171 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9172 9173 Extra roots can come from periodic cuts, where additional points appear on the boundary 9174 9175 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9176 @*/ 9177 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9178 { 9179 PetscInt l, nleaves, nroots, overlap; 9180 const PetscInt *locals; 9181 const PetscSFNode *remotes; 9182 PetscBool distributed; 9183 MPI_Comm comm; 9184 PetscMPIInt rank; 9185 9186 PetscFunctionBegin; 9187 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9188 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9189 else pointSF = dm->sf; 9190 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9191 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9192 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9193 { 9194 PetscMPIInt mpiFlag; 9195 9196 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9197 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9198 } 9199 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9200 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9201 if (!distributed) { 9202 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); 9203 PetscFunctionReturn(PETSC_SUCCESS); 9204 } 9205 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); 9206 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9207 9208 /* Check SF graph is compatible with DMPlex chart */ 9209 { 9210 PetscInt pStart, pEnd, maxLeaf; 9211 9212 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9213 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9214 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9215 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9216 } 9217 9218 /* Check Point SF has no local points referenced */ 9219 for (l = 0; l < nleaves; l++) { 9220 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); 9221 } 9222 9223 /* Check there are no cells in interface */ 9224 if (!overlap) { 9225 PetscInt cellHeight, cStart, cEnd; 9226 9227 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9228 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9229 for (l = 0; l < nleaves; ++l) { 9230 const PetscInt point = locals ? locals[l] : l; 9231 9232 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9233 } 9234 } 9235 9236 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9237 { 9238 const PetscInt *rootdegree; 9239 9240 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9241 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9242 for (l = 0; l < nleaves; ++l) { 9243 const PetscInt point = locals ? locals[l] : l; 9244 const PetscInt *cone; 9245 PetscInt coneSize, c, idx; 9246 9247 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9248 PetscCall(DMPlexGetCone(dm, point, &cone)); 9249 for (c = 0; c < coneSize; ++c) { 9250 if (!rootdegree[cone[c]]) { 9251 if (locals) { 9252 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9253 } else { 9254 idx = (cone[c] < nleaves) ? cone[c] : -1; 9255 } 9256 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9257 } 9258 } 9259 } 9260 } 9261 PetscFunctionReturn(PETSC_SUCCESS); 9262 } 9263 9264 /*@ 9265 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9266 9267 Input Parameter: 9268 . dm - The `DMPLEX` object 9269 9270 Level: developer 9271 9272 Notes: 9273 This is a useful diagnostic when creating meshes programmatically. 9274 9275 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9276 9277 Currently does not include `DMPlexCheckCellShape()`. 9278 9279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9280 @*/ 9281 PetscErrorCode DMPlexCheck(DM dm) 9282 { 9283 PetscInt cellHeight; 9284 9285 PetscFunctionBegin; 9286 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9287 PetscCall(DMPlexCheckSymmetry(dm)); 9288 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9289 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9290 PetscCall(DMPlexCheckGeometry(dm)); 9291 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9292 PetscCall(DMPlexCheckInterfaceCones(dm)); 9293 PetscFunctionReturn(PETSC_SUCCESS); 9294 } 9295 9296 typedef struct cell_stats { 9297 PetscReal min, max, sum, squaresum; 9298 PetscInt count; 9299 } cell_stats_t; 9300 9301 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9302 { 9303 PetscInt i, N = *len; 9304 9305 for (i = 0; i < N; i++) { 9306 cell_stats_t *A = (cell_stats_t *)a; 9307 cell_stats_t *B = (cell_stats_t *)b; 9308 9309 B->min = PetscMin(A->min, B->min); 9310 B->max = PetscMax(A->max, B->max); 9311 B->sum += A->sum; 9312 B->squaresum += A->squaresum; 9313 B->count += A->count; 9314 } 9315 } 9316 9317 /*@ 9318 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9319 9320 Collective 9321 9322 Input Parameters: 9323 + dm - The `DMPLEX` object 9324 . output - If true, statistics will be displayed on `stdout` 9325 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9326 9327 Level: developer 9328 9329 Notes: 9330 This is mainly intended for debugging/testing purposes. 9331 9332 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9333 9334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9335 @*/ 9336 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9337 { 9338 DM dmCoarse; 9339 cell_stats_t stats, globalStats; 9340 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9341 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9342 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9343 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9344 PetscMPIInt rank, size; 9345 9346 PetscFunctionBegin; 9347 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9348 stats.min = PETSC_MAX_REAL; 9349 stats.max = PETSC_MIN_REAL; 9350 stats.sum = stats.squaresum = 0.; 9351 stats.count = 0; 9352 9353 PetscCallMPI(MPI_Comm_size(comm, &size)); 9354 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9355 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9356 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9357 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9358 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9359 for (c = cStart; c < cEnd; c++) { 9360 PetscInt i; 9361 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9362 9363 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9364 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9365 for (i = 0; i < PetscSqr(cdim); ++i) { 9366 frobJ += J[i] * J[i]; 9367 frobInvJ += invJ[i] * invJ[i]; 9368 } 9369 cond2 = frobJ * frobInvJ; 9370 cond = PetscSqrtReal(cond2); 9371 9372 stats.min = PetscMin(stats.min, cond); 9373 stats.max = PetscMax(stats.max, cond); 9374 stats.sum += cond; 9375 stats.squaresum += cond2; 9376 stats.count++; 9377 if (output && cond > limit) { 9378 PetscSection coordSection; 9379 Vec coordsLocal; 9380 PetscScalar *coords = NULL; 9381 PetscInt Nv, d, clSize, cl, *closure = NULL; 9382 9383 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9384 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9385 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9386 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9387 for (i = 0; i < Nv / cdim; ++i) { 9388 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9389 for (d = 0; d < cdim; ++d) { 9390 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9391 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9392 } 9393 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9394 } 9395 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9396 for (cl = 0; cl < clSize * 2; cl += 2) { 9397 const PetscInt edge = closure[cl]; 9398 9399 if ((edge >= eStart) && (edge < eEnd)) { 9400 PetscReal len; 9401 9402 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9403 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9404 } 9405 } 9406 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9407 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9408 } 9409 } 9410 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9411 9412 if (size > 1) { 9413 PetscMPIInt blockLengths[2] = {4, 1}; 9414 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9415 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9416 MPI_Op statReduce; 9417 9418 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9419 PetscCallMPI(MPI_Type_commit(&statType)); 9420 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9421 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9422 PetscCallMPI(MPI_Op_free(&statReduce)); 9423 PetscCallMPI(MPI_Type_free(&statType)); 9424 } else { 9425 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9426 } 9427 if (rank == 0) { 9428 count = globalStats.count; 9429 min = globalStats.min; 9430 max = globalStats.max; 9431 mean = globalStats.sum / globalStats.count; 9432 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9433 } 9434 9435 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)); 9436 PetscCall(PetscFree2(J, invJ)); 9437 9438 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9439 if (dmCoarse) { 9440 PetscBool isplex; 9441 9442 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9443 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9444 } 9445 PetscFunctionReturn(PETSC_SUCCESS); 9446 } 9447 9448 /*@ 9449 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9450 orthogonal quality below given tolerance. 9451 9452 Collective 9453 9454 Input Parameters: 9455 + dm - The `DMPLEX` object 9456 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9457 - atol - [0, 1] Absolute tolerance for tagging cells. 9458 9459 Output Parameters: 9460 + OrthQual - `Vec` containing orthogonal quality per cell 9461 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9462 9463 Options Database Keys: 9464 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9465 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9466 9467 Level: intermediate 9468 9469 Notes: 9470 Orthogonal quality is given by the following formula\: 9471 9472 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9473 9474 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 9475 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9476 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9477 calculating the cosine of the angle between these vectors. 9478 9479 Orthogonal quality ranges from 1 (best) to 0 (worst). 9480 9481 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9482 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9483 9484 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9485 9486 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9487 @*/ 9488 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9489 { 9490 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9491 PetscInt *idx; 9492 PetscScalar *oqVals; 9493 const PetscScalar *cellGeomArr, *faceGeomArr; 9494 PetscReal *ci, *fi, *Ai; 9495 MPI_Comm comm; 9496 Vec cellgeom, facegeom; 9497 DM dmFace, dmCell; 9498 IS glob; 9499 ISLocalToGlobalMapping ltog; 9500 PetscViewer vwr; 9501 9502 PetscFunctionBegin; 9503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9504 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9505 PetscAssertPointer(OrthQual, 4); 9506 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9507 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9508 PetscCall(DMGetDimension(dm, &nc)); 9509 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9510 { 9511 DMPlexInterpolatedFlag interpFlag; 9512 9513 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9514 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9515 PetscMPIInt rank; 9516 9517 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9518 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9519 } 9520 } 9521 if (OrthQualLabel) { 9522 PetscAssertPointer(OrthQualLabel, 5); 9523 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9524 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9525 } else { 9526 *OrthQualLabel = NULL; 9527 } 9528 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9529 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9530 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9531 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9532 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9533 PetscCall(VecCreate(comm, OrthQual)); 9534 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9535 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9536 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9537 PetscCall(VecSetUp(*OrthQual)); 9538 PetscCall(ISDestroy(&glob)); 9539 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9540 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9541 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9542 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9543 PetscCall(VecGetDM(cellgeom, &dmCell)); 9544 PetscCall(VecGetDM(facegeom, &dmFace)); 9545 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9546 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9547 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9548 PetscInt cellarr[2], *adj = NULL; 9549 PetscScalar *cArr, *fArr; 9550 PetscReal minvalc = 1.0, minvalf = 1.0; 9551 PetscFVCellGeom *cg; 9552 9553 idx[cellIter] = cell - cStart; 9554 cellarr[0] = cell; 9555 /* Make indexing into cellGeom easier */ 9556 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9557 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9558 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9559 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9560 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9561 PetscInt i; 9562 const PetscInt neigh = adj[cellneigh]; 9563 PetscReal normci = 0, normfi = 0, normai = 0; 9564 PetscFVCellGeom *cgneigh; 9565 PetscFVFaceGeom *fg; 9566 9567 /* Don't count ourselves in the neighbor list */ 9568 if (neigh == cell) continue; 9569 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9570 cellarr[1] = neigh; 9571 { 9572 PetscInt numcovpts; 9573 const PetscInt *covpts; 9574 9575 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9576 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9577 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9578 } 9579 9580 /* Compute c_i, f_i and their norms */ 9581 for (i = 0; i < nc; i++) { 9582 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9583 fi[i] = fg->centroid[i] - cg->centroid[i]; 9584 Ai[i] = fg->normal[i]; 9585 normci += PetscPowReal(ci[i], 2); 9586 normfi += PetscPowReal(fi[i], 2); 9587 normai += PetscPowReal(Ai[i], 2); 9588 } 9589 normci = PetscSqrtReal(normci); 9590 normfi = PetscSqrtReal(normfi); 9591 normai = PetscSqrtReal(normai); 9592 9593 /* Normalize and compute for each face-cell-normal pair */ 9594 for (i = 0; i < nc; i++) { 9595 ci[i] = ci[i] / normci; 9596 fi[i] = fi[i] / normfi; 9597 Ai[i] = Ai[i] / normai; 9598 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9599 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9600 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9601 } 9602 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9603 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9604 } 9605 PetscCall(PetscFree(adj)); 9606 PetscCall(PetscFree2(cArr, fArr)); 9607 /* Defer to cell if they're equal */ 9608 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9609 if (OrthQualLabel) { 9610 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9611 } 9612 } 9613 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9614 PetscCall(VecAssemblyBegin(*OrthQual)); 9615 PetscCall(VecAssemblyEnd(*OrthQual)); 9616 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9617 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9618 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9619 if (OrthQualLabel) { 9620 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9621 } 9622 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9623 PetscCall(PetscViewerDestroy(&vwr)); 9624 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9625 PetscFunctionReturn(PETSC_SUCCESS); 9626 } 9627 9628 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9629 * interpolator construction */ 9630 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9631 { 9632 PetscSection section, newSection, gsection; 9633 PetscSF sf; 9634 PetscBool hasConstraints, ghasConstraints; 9635 9636 PetscFunctionBegin; 9637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9638 PetscAssertPointer(odm, 2); 9639 PetscCall(DMGetLocalSection(dm, §ion)); 9640 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9641 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9642 if (!ghasConstraints) { 9643 PetscCall(PetscObjectReference((PetscObject)dm)); 9644 *odm = dm; 9645 PetscFunctionReturn(PETSC_SUCCESS); 9646 } 9647 PetscCall(DMClone(dm, odm)); 9648 PetscCall(DMCopyFields(dm, *odm)); 9649 PetscCall(DMGetLocalSection(*odm, &newSection)); 9650 PetscCall(DMGetPointSF(*odm, &sf)); 9651 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9652 PetscCall(DMSetGlobalSection(*odm, gsection)); 9653 PetscCall(PetscSectionDestroy(&gsection)); 9654 PetscFunctionReturn(PETSC_SUCCESS); 9655 } 9656 9657 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9658 { 9659 DM dmco, dmfo; 9660 Mat interpo; 9661 Vec rscale; 9662 Vec cglobalo, clocal; 9663 Vec fglobal, fglobalo, flocal; 9664 PetscBool regular; 9665 9666 PetscFunctionBegin; 9667 PetscCall(DMGetFullDM(dmc, &dmco)); 9668 PetscCall(DMGetFullDM(dmf, &dmfo)); 9669 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9670 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9671 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9672 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9673 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9674 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9675 PetscCall(VecSet(cglobalo, 0.)); 9676 PetscCall(VecSet(clocal, 0.)); 9677 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9678 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9679 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9680 PetscCall(VecSet(fglobal, 0.)); 9681 PetscCall(VecSet(fglobalo, 0.)); 9682 PetscCall(VecSet(flocal, 0.)); 9683 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9684 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9685 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9686 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9687 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9688 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9689 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9690 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9691 *shift = fglobal; 9692 PetscCall(VecDestroy(&flocal)); 9693 PetscCall(VecDestroy(&fglobalo)); 9694 PetscCall(VecDestroy(&clocal)); 9695 PetscCall(VecDestroy(&cglobalo)); 9696 PetscCall(VecDestroy(&rscale)); 9697 PetscCall(MatDestroy(&interpo)); 9698 PetscCall(DMDestroy(&dmfo)); 9699 PetscCall(DMDestroy(&dmco)); 9700 PetscFunctionReturn(PETSC_SUCCESS); 9701 } 9702 9703 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9704 { 9705 PetscObject shifto; 9706 Vec shift; 9707 9708 PetscFunctionBegin; 9709 if (!interp) { 9710 Vec rscale; 9711 9712 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9713 PetscCall(VecDestroy(&rscale)); 9714 } else { 9715 PetscCall(PetscObjectReference((PetscObject)interp)); 9716 } 9717 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9718 if (!shifto) { 9719 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9720 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9721 shifto = (PetscObject)shift; 9722 PetscCall(VecDestroy(&shift)); 9723 } 9724 shift = (Vec)shifto; 9725 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9726 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9727 PetscCall(MatDestroy(&interp)); 9728 PetscFunctionReturn(PETSC_SUCCESS); 9729 } 9730 9731 /* Pointwise interpolation 9732 Just code FEM for now 9733 u^f = I u^c 9734 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9735 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9736 I_{ij} = psi^f_i phi^c_j 9737 */ 9738 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9739 { 9740 PetscSection gsc, gsf; 9741 PetscInt m, n; 9742 void *ctx; 9743 DM cdm; 9744 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9745 9746 PetscFunctionBegin; 9747 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9748 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9749 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9750 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9751 9752 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9753 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9754 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9755 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9756 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9757 9758 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9759 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9760 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9761 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9762 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9763 if (scaling) { 9764 /* Use naive scaling */ 9765 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9766 } 9767 PetscFunctionReturn(PETSC_SUCCESS); 9768 } 9769 9770 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9771 { 9772 VecScatter ctx; 9773 9774 PetscFunctionBegin; 9775 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9776 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9777 PetscCall(VecScatterDestroy(&ctx)); 9778 PetscFunctionReturn(PETSC_SUCCESS); 9779 } 9780 9781 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[]) 9782 { 9783 const PetscInt Nc = uOff[1] - uOff[0]; 9784 PetscInt c; 9785 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9786 } 9787 9788 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9789 { 9790 DM dmc; 9791 PetscDS ds; 9792 Vec ones, locmass; 9793 IS cellIS; 9794 PetscFormKey key; 9795 PetscInt depth; 9796 9797 PetscFunctionBegin; 9798 PetscCall(DMClone(dm, &dmc)); 9799 PetscCall(DMCopyDisc(dm, dmc)); 9800 PetscCall(DMGetDS(dmc, &ds)); 9801 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9802 PetscCall(DMCreateGlobalVector(dmc, mass)); 9803 PetscCall(DMGetLocalVector(dmc, &ones)); 9804 PetscCall(DMGetLocalVector(dmc, &locmass)); 9805 PetscCall(DMPlexGetDepth(dmc, &depth)); 9806 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9807 PetscCall(VecSet(locmass, 0.0)); 9808 PetscCall(VecSet(ones, 1.0)); 9809 key.label = NULL; 9810 key.value = 0; 9811 key.field = 0; 9812 key.part = 0; 9813 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9814 PetscCall(ISDestroy(&cellIS)); 9815 PetscCall(VecSet(*mass, 0.0)); 9816 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9817 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9818 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9819 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9820 PetscCall(DMDestroy(&dmc)); 9821 PetscFunctionReturn(PETSC_SUCCESS); 9822 } 9823 9824 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9825 { 9826 PetscSection gsc, gsf; 9827 PetscInt m, n; 9828 void *ctx; 9829 DM cdm; 9830 PetscBool regular; 9831 9832 PetscFunctionBegin; 9833 if (dmFine == dmCoarse) { 9834 DM dmc; 9835 PetscDS ds; 9836 PetscWeakForm wf; 9837 Vec u; 9838 IS cellIS; 9839 PetscFormKey key; 9840 PetscInt depth; 9841 9842 PetscCall(DMClone(dmFine, &dmc)); 9843 PetscCall(DMCopyDisc(dmFine, dmc)); 9844 PetscCall(DMGetDS(dmc, &ds)); 9845 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9846 PetscCall(PetscWeakFormClear(wf)); 9847 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9848 PetscCall(DMCreateMatrix(dmc, mass)); 9849 PetscCall(DMGetLocalVector(dmc, &u)); 9850 PetscCall(DMPlexGetDepth(dmc, &depth)); 9851 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9852 PetscCall(MatZeroEntries(*mass)); 9853 key.label = NULL; 9854 key.value = 0; 9855 key.field = 0; 9856 key.part = 0; 9857 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9858 PetscCall(ISDestroy(&cellIS)); 9859 PetscCall(DMRestoreLocalVector(dmc, &u)); 9860 PetscCall(DMDestroy(&dmc)); 9861 } else { 9862 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9863 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9864 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9865 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9866 9867 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9868 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9869 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9870 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9871 9872 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9873 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9874 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9875 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9876 } 9877 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9878 PetscFunctionReturn(PETSC_SUCCESS); 9879 } 9880 9881 /*@ 9882 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9883 9884 Input Parameter: 9885 . dm - The `DMPLEX` object 9886 9887 Output Parameter: 9888 . regular - The flag 9889 9890 Level: intermediate 9891 9892 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9893 @*/ 9894 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9895 { 9896 PetscFunctionBegin; 9897 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9898 PetscAssertPointer(regular, 2); 9899 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9900 PetscFunctionReturn(PETSC_SUCCESS); 9901 } 9902 9903 /*@ 9904 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9905 9906 Input Parameters: 9907 + dm - The `DMPLEX` object 9908 - regular - The flag 9909 9910 Level: intermediate 9911 9912 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9913 @*/ 9914 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9915 { 9916 PetscFunctionBegin; 9917 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9918 ((DM_Plex *)dm->data)->regularRefinement = regular; 9919 PetscFunctionReturn(PETSC_SUCCESS); 9920 } 9921 9922 /*@ 9923 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9924 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9925 9926 Not Collective 9927 9928 Input Parameter: 9929 . dm - The `DMPLEX` object 9930 9931 Output Parameters: 9932 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9933 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 9934 9935 Level: intermediate 9936 9937 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9938 @*/ 9939 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9940 { 9941 DM_Plex *plex = (DM_Plex *)dm->data; 9942 9943 PetscFunctionBegin; 9944 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9945 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9946 if (anchorSection) *anchorSection = plex->anchorSection; 9947 if (anchorIS) *anchorIS = plex->anchorIS; 9948 PetscFunctionReturn(PETSC_SUCCESS); 9949 } 9950 9951 /*@ 9952 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 9953 9954 Collective 9955 9956 Input Parameters: 9957 + dm - The `DMPLEX` object 9958 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9959 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9960 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9961 9962 Level: intermediate 9963 9964 Notes: 9965 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 9966 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 9967 combination of other points' degrees of freedom. 9968 9969 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9970 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9971 9972 The reference counts of `anchorSection` and `anchorIS` are incremented. 9973 9974 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9975 @*/ 9976 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9977 { 9978 DM_Plex *plex = (DM_Plex *)dm->data; 9979 PetscMPIInt result; 9980 9981 PetscFunctionBegin; 9982 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9983 if (anchorSection) { 9984 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9985 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9986 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9987 } 9988 if (anchorIS) { 9989 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9990 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9991 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9992 } 9993 9994 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9995 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9996 plex->anchorSection = anchorSection; 9997 9998 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9999 PetscCall(ISDestroy(&plex->anchorIS)); 10000 plex->anchorIS = anchorIS; 10001 10002 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10003 PetscInt size, a, pStart, pEnd; 10004 const PetscInt *anchors; 10005 10006 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10007 PetscCall(ISGetLocalSize(anchorIS, &size)); 10008 PetscCall(ISGetIndices(anchorIS, &anchors)); 10009 for (a = 0; a < size; a++) { 10010 PetscInt p; 10011 10012 p = anchors[a]; 10013 if (p >= pStart && p < pEnd) { 10014 PetscInt dof; 10015 10016 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10017 if (dof) { 10018 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10019 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10020 } 10021 } 10022 } 10023 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10024 } 10025 /* reset the generic constraints */ 10026 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10027 PetscFunctionReturn(PETSC_SUCCESS); 10028 } 10029 10030 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10031 { 10032 PetscSection anchorSection; 10033 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10034 10035 PetscFunctionBegin; 10036 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10037 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10038 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10039 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10040 if (numFields) { 10041 PetscInt f; 10042 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10043 10044 for (f = 0; f < numFields; f++) { 10045 PetscInt numComp; 10046 10047 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10048 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10049 } 10050 } 10051 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10052 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10053 pStart = PetscMax(pStart, sStart); 10054 pEnd = PetscMin(pEnd, sEnd); 10055 pEnd = PetscMax(pStart, pEnd); 10056 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10057 for (p = pStart; p < pEnd; p++) { 10058 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10059 if (dof) { 10060 PetscCall(PetscSectionGetDof(section, p, &dof)); 10061 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10062 for (f = 0; f < numFields; f++) { 10063 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10064 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10065 } 10066 } 10067 } 10068 PetscCall(PetscSectionSetUp(*cSec)); 10069 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10070 PetscFunctionReturn(PETSC_SUCCESS); 10071 } 10072 10073 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10074 { 10075 PetscSection aSec; 10076 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10077 const PetscInt *anchors; 10078 PetscInt numFields, f; 10079 IS aIS; 10080 MatType mtype; 10081 PetscBool iscuda, iskokkos; 10082 10083 PetscFunctionBegin; 10084 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10085 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10086 PetscCall(PetscSectionGetStorageSize(section, &n)); 10087 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10088 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10089 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10090 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10091 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10092 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10093 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10094 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10095 else mtype = MATSEQAIJ; 10096 PetscCall(MatSetType(*cMat, mtype)); 10097 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10098 PetscCall(ISGetIndices(aIS, &anchors)); 10099 /* cSec will be a subset of aSec and section */ 10100 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10101 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10102 PetscCall(PetscMalloc1(m + 1, &i)); 10103 i[0] = 0; 10104 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10105 for (p = pStart; p < pEnd; p++) { 10106 PetscInt rDof, rOff, r; 10107 10108 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10109 if (!rDof) continue; 10110 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10111 if (numFields) { 10112 for (f = 0; f < numFields; f++) { 10113 annz = 0; 10114 for (r = 0; r < rDof; r++) { 10115 a = anchors[rOff + r]; 10116 if (a < sStart || a >= sEnd) continue; 10117 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10118 annz += aDof; 10119 } 10120 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10121 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10122 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10123 } 10124 } else { 10125 annz = 0; 10126 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10127 for (q = 0; q < dof; q++) { 10128 a = anchors[rOff + q]; 10129 if (a < sStart || a >= sEnd) continue; 10130 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10131 annz += aDof; 10132 } 10133 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10134 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10135 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10136 } 10137 } 10138 nnz = i[m]; 10139 PetscCall(PetscMalloc1(nnz, &j)); 10140 offset = 0; 10141 for (p = pStart; p < pEnd; p++) { 10142 if (numFields) { 10143 for (f = 0; f < numFields; f++) { 10144 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10145 for (q = 0; q < dof; q++) { 10146 PetscInt rDof, rOff, r; 10147 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10148 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10149 for (r = 0; r < rDof; r++) { 10150 PetscInt s; 10151 10152 a = anchors[rOff + r]; 10153 if (a < sStart || a >= sEnd) continue; 10154 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10155 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10156 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10157 } 10158 } 10159 } 10160 } else { 10161 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10162 for (q = 0; q < dof; q++) { 10163 PetscInt rDof, rOff, r; 10164 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10165 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10166 for (r = 0; r < rDof; r++) { 10167 PetscInt s; 10168 10169 a = anchors[rOff + r]; 10170 if (a < sStart || a >= sEnd) continue; 10171 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10172 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10173 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10174 } 10175 } 10176 } 10177 } 10178 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10179 PetscCall(PetscFree(i)); 10180 PetscCall(PetscFree(j)); 10181 PetscCall(ISRestoreIndices(aIS, &anchors)); 10182 PetscFunctionReturn(PETSC_SUCCESS); 10183 } 10184 10185 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10186 { 10187 DM_Plex *plex = (DM_Plex *)dm->data; 10188 PetscSection anchorSection, section, cSec; 10189 Mat cMat; 10190 10191 PetscFunctionBegin; 10192 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10193 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10194 if (anchorSection) { 10195 PetscInt Nf; 10196 10197 PetscCall(DMGetLocalSection(dm, §ion)); 10198 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10199 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10200 PetscCall(DMGetNumFields(dm, &Nf)); 10201 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10202 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10203 PetscCall(PetscSectionDestroy(&cSec)); 10204 PetscCall(MatDestroy(&cMat)); 10205 } 10206 PetscFunctionReturn(PETSC_SUCCESS); 10207 } 10208 10209 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10210 { 10211 IS subis; 10212 PetscSection section, subsection; 10213 10214 PetscFunctionBegin; 10215 PetscCall(DMGetLocalSection(dm, §ion)); 10216 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10217 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10218 /* Create subdomain */ 10219 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10220 /* Create submodel */ 10221 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10222 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10223 PetscCall(DMSetLocalSection(*subdm, subsection)); 10224 PetscCall(PetscSectionDestroy(&subsection)); 10225 PetscCall(DMCopyDisc(dm, *subdm)); 10226 /* Create map from submodel to global model */ 10227 if (is) { 10228 PetscSection sectionGlobal, subsectionGlobal; 10229 IS spIS; 10230 const PetscInt *spmap; 10231 PetscInt *subIndices; 10232 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10233 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10234 10235 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10236 PetscCall(ISGetIndices(spIS, &spmap)); 10237 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10238 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10239 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10240 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10241 for (p = pStart; p < pEnd; ++p) { 10242 PetscInt gdof, pSubSize = 0; 10243 10244 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10245 if (gdof > 0) { 10246 for (f = 0; f < Nf; ++f) { 10247 PetscInt fdof, fcdof; 10248 10249 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10250 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10251 pSubSize += fdof - fcdof; 10252 } 10253 subSize += pSubSize; 10254 if (pSubSize) { 10255 if (bs < 0) { 10256 bs = pSubSize; 10257 } else if (bs != pSubSize) { 10258 /* Layout does not admit a pointwise block size */ 10259 bs = 1; 10260 } 10261 } 10262 } 10263 } 10264 /* Must have same blocksize on all procs (some might have no points) */ 10265 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10266 bsLocal[1] = bs; 10267 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10268 if (bsMinMax[0] != bsMinMax[1]) { 10269 bs = 1; 10270 } else { 10271 bs = bsMinMax[0]; 10272 } 10273 PetscCall(PetscMalloc1(subSize, &subIndices)); 10274 for (p = pStart; p < pEnd; ++p) { 10275 PetscInt gdof, goff; 10276 10277 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10278 if (gdof > 0) { 10279 const PetscInt point = spmap[p]; 10280 10281 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10282 for (f = 0; f < Nf; ++f) { 10283 PetscInt fdof, fcdof, fc, f2, poff = 0; 10284 10285 /* Can get rid of this loop by storing field information in the global section */ 10286 for (f2 = 0; f2 < f; ++f2) { 10287 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10288 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10289 poff += fdof - fcdof; 10290 } 10291 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10292 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10293 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10294 } 10295 } 10296 } 10297 PetscCall(ISRestoreIndices(spIS, &spmap)); 10298 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10299 if (bs > 1) { 10300 /* We need to check that the block size does not come from non-contiguous fields */ 10301 PetscInt i, j, set = 1; 10302 for (i = 0; i < subSize; i += bs) { 10303 for (j = 0; j < bs; ++j) { 10304 if (subIndices[i + j] != subIndices[i] + j) { 10305 set = 0; 10306 break; 10307 } 10308 } 10309 } 10310 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10311 } 10312 /* Attach nullspace */ 10313 for (f = 0; f < Nf; ++f) { 10314 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10315 if ((*subdm)->nullspaceConstructors[f]) break; 10316 } 10317 if (f < Nf) { 10318 MatNullSpace nullSpace; 10319 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10320 10321 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10322 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10323 } 10324 } 10325 PetscFunctionReturn(PETSC_SUCCESS); 10326 } 10327 10328 /*@ 10329 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10330 10331 Input Parameters: 10332 + dm - The `DM` 10333 - dummy - unused argument 10334 10335 Options Database Key: 10336 . -dm_plex_monitor_throughput - Activate the monitor 10337 10338 Level: developer 10339 10340 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10341 @*/ 10342 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10343 { 10344 PetscLogHandler default_handler; 10345 10346 PetscFunctionBegin; 10347 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10348 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10349 if (default_handler) { 10350 PetscLogEvent event; 10351 PetscEventPerfInfo eventInfo; 10352 PetscReal cellRate, flopRate; 10353 PetscInt cStart, cEnd, Nf, N; 10354 const char *name; 10355 10356 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10357 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10358 PetscCall(DMGetNumFields(dm, &Nf)); 10359 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10360 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10361 N = (cEnd - cStart) * Nf * eventInfo.count; 10362 flopRate = eventInfo.flops / eventInfo.time; 10363 cellRate = N / eventInfo.time; 10364 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))); 10365 } else { 10366 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."); 10367 } 10368 PetscFunctionReturn(PETSC_SUCCESS); 10369 } 10370