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 /* 5552 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5553 representing a line in the section. 5554 */ 5555 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5556 { 5557 PetscFunctionBeginHot; 5558 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5559 if (line < 0) { 5560 *k = 0; 5561 *Nc = 0; 5562 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5563 *k = 1; 5564 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5565 /* An order k SEM disc has k-1 dofs on an edge */ 5566 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5567 *k = *k / *Nc + 1; 5568 } 5569 PetscFunctionReturn(PETSC_SUCCESS); 5570 } 5571 5572 /*@ 5573 5574 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5575 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5576 section provided (or the section of the `DM`). 5577 5578 Input Parameters: 5579 + dm - The `DM` 5580 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5581 - section - The `PetscSection` to reorder, or `NULL` for the default section 5582 5583 Example: 5584 A typical interpolated single-quad mesh might order points as 5585 .vb 5586 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5587 5588 v4 -- e6 -- v3 5589 | | 5590 e7 c0 e8 5591 | | 5592 v1 -- e5 -- v2 5593 .ve 5594 5595 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5596 dofs in the order of points, e.g., 5597 .vb 5598 c0 -> [0,1,2,3] 5599 v1 -> [4] 5600 ... 5601 e5 -> [8, 9] 5602 .ve 5603 5604 which corresponds to the dofs 5605 .vb 5606 6 10 11 7 5607 13 2 3 15 5608 12 0 1 14 5609 4 8 9 5 5610 .ve 5611 5612 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5613 .vb 5614 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5615 .ve 5616 5617 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5618 .vb 5619 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5620 .ve 5621 5622 Level: developer 5623 5624 Notes: 5625 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5626 degree of the basis. 5627 5628 This is required to run with libCEED. 5629 5630 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5631 @*/ 5632 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5633 { 5634 DMLabel label; 5635 PetscInt dim, depth = -1, eStart = -1, Nf; 5636 PetscBool vertexchart; 5637 5638 PetscFunctionBegin; 5639 PetscCall(DMGetDimension(dm, &dim)); 5640 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5641 if (point < 0) { 5642 PetscInt sStart, sEnd; 5643 5644 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5645 point = sEnd - sStart ? sStart : point; 5646 } 5647 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5648 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5649 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5650 if (depth == 1) { 5651 eStart = point; 5652 } else if (depth == dim) { 5653 const PetscInt *cone; 5654 5655 PetscCall(DMPlexGetCone(dm, point, &cone)); 5656 if (dim == 2) eStart = cone[0]; 5657 else if (dim == 3) { 5658 const PetscInt *cone2; 5659 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5660 eStart = cone2[0]; 5661 } 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); 5662 } 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); 5663 { /* Determine whether the chart covers all points or just vertices. */ 5664 PetscInt pStart, pEnd, cStart, cEnd; 5665 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5666 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5667 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5668 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5669 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5670 } 5671 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5672 for (PetscInt d = 1; d <= dim; d++) { 5673 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5674 PetscInt *perm; 5675 5676 for (f = 0; f < Nf; ++f) { 5677 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5678 size += PetscPowInt(k + 1, d) * Nc; 5679 } 5680 PetscCall(PetscMalloc1(size, &perm)); 5681 for (f = 0; f < Nf; ++f) { 5682 switch (d) { 5683 case 1: 5684 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5685 /* 5686 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5687 We want [ vtx0; edge of length k-1; vtx1 ] 5688 */ 5689 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5690 for (i = 0; i < k - 1; i++) 5691 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5692 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5693 foffset = offset; 5694 break; 5695 case 2: 5696 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5697 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5698 /* The SEM order is 5699 5700 v_lb, {e_b}, v_rb, 5701 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5702 v_lt, reverse {e_t}, v_rt 5703 */ 5704 { 5705 const PetscInt of = 0; 5706 const PetscInt oeb = of + PetscSqr(k - 1); 5707 const PetscInt oer = oeb + (k - 1); 5708 const PetscInt oet = oer + (k - 1); 5709 const PetscInt oel = oet + (k - 1); 5710 const PetscInt ovlb = oel + (k - 1); 5711 const PetscInt ovrb = ovlb + 1; 5712 const PetscInt ovrt = ovrb + 1; 5713 const PetscInt ovlt = ovrt + 1; 5714 PetscInt o; 5715 5716 /* bottom */ 5717 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5718 for (o = oeb; o < oer; ++o) 5719 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5720 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5721 /* middle */ 5722 for (i = 0; i < k - 1; ++i) { 5723 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5724 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5725 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5726 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5727 } 5728 /* top */ 5729 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5730 for (o = oel - 1; o >= oet; --o) 5731 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5732 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5733 foffset = offset; 5734 } 5735 break; 5736 case 3: 5737 /* The original hex closure is 5738 5739 {c, 5740 f_b, f_t, f_f, f_b, f_r, f_l, 5741 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5742 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5743 */ 5744 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5745 /* The SEM order is 5746 Bottom Slice 5747 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5748 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5749 v_blb, {e_bb}, v_brb, 5750 5751 Middle Slice (j) 5752 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5753 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5754 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5755 5756 Top Slice 5757 v_tlf, {e_tf}, v_trf, 5758 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5759 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5760 */ 5761 { 5762 const PetscInt oc = 0; 5763 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5764 const PetscInt oft = ofb + PetscSqr(k - 1); 5765 const PetscInt off = oft + PetscSqr(k - 1); 5766 const PetscInt ofk = off + PetscSqr(k - 1); 5767 const PetscInt ofr = ofk + PetscSqr(k - 1); 5768 const PetscInt ofl = ofr + PetscSqr(k - 1); 5769 const PetscInt oebl = ofl + PetscSqr(k - 1); 5770 const PetscInt oebb = oebl + (k - 1); 5771 const PetscInt oebr = oebb + (k - 1); 5772 const PetscInt oebf = oebr + (k - 1); 5773 const PetscInt oetf = oebf + (k - 1); 5774 const PetscInt oetr = oetf + (k - 1); 5775 const PetscInt oetb = oetr + (k - 1); 5776 const PetscInt oetl = oetb + (k - 1); 5777 const PetscInt oerf = oetl + (k - 1); 5778 const PetscInt oelf = oerf + (k - 1); 5779 const PetscInt oelb = oelf + (k - 1); 5780 const PetscInt oerb = oelb + (k - 1); 5781 const PetscInt ovblf = oerb + (k - 1); 5782 const PetscInt ovblb = ovblf + 1; 5783 const PetscInt ovbrb = ovblb + 1; 5784 const PetscInt ovbrf = ovbrb + 1; 5785 const PetscInt ovtlf = ovbrf + 1; 5786 const PetscInt ovtrf = ovtlf + 1; 5787 const PetscInt ovtrb = ovtrf + 1; 5788 const PetscInt ovtlb = ovtrb + 1; 5789 PetscInt o, n; 5790 5791 /* Bottom Slice */ 5792 /* bottom */ 5793 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5794 for (o = oetf - 1; o >= oebf; --o) 5795 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5796 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5797 /* middle */ 5798 for (i = 0; i < k - 1; ++i) { 5799 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5800 for (n = 0; n < k - 1; ++n) { 5801 o = ofb + n * (k - 1) + i; 5802 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5803 } 5804 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5805 } 5806 /* top */ 5807 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5808 for (o = oebb; o < oebr; ++o) 5809 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5810 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5811 5812 /* Middle Slice */ 5813 for (j = 0; j < k - 1; ++j) { 5814 /* bottom */ 5815 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5816 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5817 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5818 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5819 /* middle */ 5820 for (i = 0; i < k - 1; ++i) { 5821 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5822 for (n = 0; n < k - 1; ++n) 5823 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5824 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5825 } 5826 /* top */ 5827 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5828 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5829 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5830 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5831 } 5832 5833 /* Top Slice */ 5834 /* bottom */ 5835 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5836 for (o = oetf; o < oetr; ++o) 5837 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5838 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5839 /* middle */ 5840 for (i = 0; i < k - 1; ++i) { 5841 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5842 for (n = 0; n < k - 1; ++n) 5843 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5844 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5845 } 5846 /* top */ 5847 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5848 for (o = oetl - 1; o >= oetb; --o) 5849 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5850 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5851 5852 foffset = offset; 5853 } 5854 break; 5855 default: 5856 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5857 } 5858 } 5859 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5860 /* Check permutation */ 5861 { 5862 PetscInt *check; 5863 5864 PetscCall(PetscMalloc1(size, &check)); 5865 for (i = 0; i < size; ++i) { 5866 check[i] = -1; 5867 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5868 } 5869 for (i = 0; i < size; ++i) check[perm[i]] = i; 5870 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5871 PetscCall(PetscFree(check)); 5872 } 5873 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5874 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5875 PetscInt *loc_perm; 5876 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5877 for (PetscInt i = 0; i < size; i++) { 5878 loc_perm[i] = perm[i]; 5879 loc_perm[size + i] = size + perm[i]; 5880 } 5881 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5882 } 5883 } 5884 PetscFunctionReturn(PETSC_SUCCESS); 5885 } 5886 5887 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5888 { 5889 PetscDS prob; 5890 PetscInt depth, Nf, h; 5891 DMLabel label; 5892 5893 PetscFunctionBeginHot; 5894 PetscCall(DMGetDS(dm, &prob)); 5895 Nf = prob->Nf; 5896 label = dm->depthLabel; 5897 *dspace = NULL; 5898 if (field < Nf) { 5899 PetscObject disc = prob->disc[field]; 5900 5901 if (disc->classid == PETSCFE_CLASSID) { 5902 PetscDualSpace dsp; 5903 5904 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5905 PetscCall(DMLabelGetNumValues(label, &depth)); 5906 PetscCall(DMLabelGetValue(label, point, &h)); 5907 h = depth - 1 - h; 5908 if (h) { 5909 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5910 } else { 5911 *dspace = dsp; 5912 } 5913 } 5914 } 5915 PetscFunctionReturn(PETSC_SUCCESS); 5916 } 5917 5918 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5919 { 5920 PetscScalar *array; 5921 const PetscScalar *vArray; 5922 const PetscInt *cone, *coneO; 5923 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5924 5925 PetscFunctionBeginHot; 5926 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5927 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5928 PetscCall(DMPlexGetCone(dm, point, &cone)); 5929 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5930 if (!values || !*values) { 5931 if ((point >= pStart) && (point < pEnd)) { 5932 PetscInt dof; 5933 5934 PetscCall(PetscSectionGetDof(section, point, &dof)); 5935 size += dof; 5936 } 5937 for (p = 0; p < numPoints; ++p) { 5938 const PetscInt cp = cone[p]; 5939 PetscInt dof; 5940 5941 if ((cp < pStart) || (cp >= pEnd)) continue; 5942 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5943 size += dof; 5944 } 5945 if (!values) { 5946 if (csize) *csize = size; 5947 PetscFunctionReturn(PETSC_SUCCESS); 5948 } 5949 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5950 } else { 5951 array = *values; 5952 } 5953 size = 0; 5954 PetscCall(VecGetArrayRead(v, &vArray)); 5955 if ((point >= pStart) && (point < pEnd)) { 5956 PetscInt dof, off, d; 5957 const PetscScalar *varr; 5958 5959 PetscCall(PetscSectionGetDof(section, point, &dof)); 5960 PetscCall(PetscSectionGetOffset(section, point, &off)); 5961 varr = &vArray[off]; 5962 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5963 size += dof; 5964 } 5965 for (p = 0; p < numPoints; ++p) { 5966 const PetscInt cp = cone[p]; 5967 PetscInt o = coneO[p]; 5968 PetscInt dof, off, d; 5969 const PetscScalar *varr; 5970 5971 if ((cp < pStart) || (cp >= pEnd)) continue; 5972 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5973 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5974 varr = &vArray[off]; 5975 if (o >= 0) { 5976 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5977 } else { 5978 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5979 } 5980 size += dof; 5981 } 5982 PetscCall(VecRestoreArrayRead(v, &vArray)); 5983 if (!*values) { 5984 if (csize) *csize = size; 5985 *values = array; 5986 } else { 5987 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5988 *csize = size; 5989 } 5990 PetscFunctionReturn(PETSC_SUCCESS); 5991 } 5992 5993 /* Compress out points not in the section */ 5994 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5995 { 5996 const PetscInt np = *numPoints; 5997 PetscInt pStart, pEnd, p, q; 5998 5999 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6000 for (p = 0, q = 0; p < np; ++p) { 6001 const PetscInt r = points[p * 2]; 6002 if ((r >= pStart) && (r < pEnd)) { 6003 points[q * 2] = r; 6004 points[q * 2 + 1] = points[p * 2 + 1]; 6005 ++q; 6006 } 6007 } 6008 *numPoints = q; 6009 return PETSC_SUCCESS; 6010 } 6011 6012 /* Compressed closure does not apply closure permutation */ 6013 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6014 { 6015 const PetscInt *cla = NULL; 6016 PetscInt np, *pts = NULL; 6017 6018 PetscFunctionBeginHot; 6019 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6020 if (!ornt && *clPoints) { 6021 PetscInt dof, off; 6022 6023 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6024 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6025 PetscCall(ISGetIndices(*clPoints, &cla)); 6026 np = dof / 2; 6027 pts = (PetscInt *)&cla[off]; 6028 } else { 6029 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6030 PetscCall(CompressPoints_Private(section, &np, pts)); 6031 } 6032 *numPoints = np; 6033 *points = pts; 6034 *clp = cla; 6035 PetscFunctionReturn(PETSC_SUCCESS); 6036 } 6037 6038 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6039 { 6040 PetscFunctionBeginHot; 6041 if (!*clPoints) { 6042 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6043 } else { 6044 PetscCall(ISRestoreIndices(*clPoints, clp)); 6045 } 6046 *numPoints = 0; 6047 *points = NULL; 6048 *clSec = NULL; 6049 *clPoints = NULL; 6050 *clp = NULL; 6051 PetscFunctionReturn(PETSC_SUCCESS); 6052 } 6053 6054 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6055 { 6056 PetscInt offset = 0, p; 6057 const PetscInt **perms = NULL; 6058 const PetscScalar **flips = NULL; 6059 6060 PetscFunctionBeginHot; 6061 *size = 0; 6062 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6063 for (p = 0; p < numPoints; p++) { 6064 const PetscInt point = points[2 * p]; 6065 const PetscInt *perm = perms ? perms[p] : NULL; 6066 const PetscScalar *flip = flips ? flips[p] : NULL; 6067 PetscInt dof, off, d; 6068 const PetscScalar *varr; 6069 6070 PetscCall(PetscSectionGetDof(section, point, &dof)); 6071 PetscCall(PetscSectionGetOffset(section, point, &off)); 6072 varr = &vArray[off]; 6073 if (clperm) { 6074 if (perm) { 6075 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6076 } else { 6077 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6078 } 6079 if (flip) { 6080 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6081 } 6082 } else { 6083 if (perm) { 6084 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6085 } else { 6086 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6087 } 6088 if (flip) { 6089 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6090 } 6091 } 6092 offset += dof; 6093 } 6094 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6095 *size = offset; 6096 PetscFunctionReturn(PETSC_SUCCESS); 6097 } 6098 6099 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[]) 6100 { 6101 PetscInt offset = 0, f; 6102 6103 PetscFunctionBeginHot; 6104 *size = 0; 6105 for (f = 0; f < numFields; ++f) { 6106 PetscInt p; 6107 const PetscInt **perms = NULL; 6108 const PetscScalar **flips = NULL; 6109 6110 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6111 for (p = 0; p < numPoints; p++) { 6112 const PetscInt point = points[2 * p]; 6113 PetscInt fdof, foff, b; 6114 const PetscScalar *varr; 6115 const PetscInt *perm = perms ? perms[p] : NULL; 6116 const PetscScalar *flip = flips ? flips[p] : NULL; 6117 6118 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6119 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6120 varr = &vArray[foff]; 6121 if (clperm) { 6122 if (perm) { 6123 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6124 } else { 6125 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6126 } 6127 if (flip) { 6128 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6129 } 6130 } else { 6131 if (perm) { 6132 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6133 } else { 6134 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6135 } 6136 if (flip) { 6137 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6138 } 6139 } 6140 offset += fdof; 6141 } 6142 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6143 } 6144 *size = offset; 6145 PetscFunctionReturn(PETSC_SUCCESS); 6146 } 6147 6148 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6149 { 6150 PetscSection clSection; 6151 IS clPoints; 6152 PetscInt *points = NULL; 6153 const PetscInt *clp, *perm = NULL; 6154 PetscInt depth, numFields, numPoints, asize; 6155 6156 PetscFunctionBeginHot; 6157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6158 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6159 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6160 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6161 PetscCall(DMPlexGetDepth(dm, &depth)); 6162 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6163 if (depth == 1 && numFields < 2) { 6164 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6165 PetscFunctionReturn(PETSC_SUCCESS); 6166 } 6167 /* Get points */ 6168 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6169 /* Get sizes */ 6170 asize = 0; 6171 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6172 PetscInt dof; 6173 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6174 asize += dof; 6175 } 6176 if (values) { 6177 const PetscScalar *vArray; 6178 PetscInt size; 6179 6180 if (*values) { 6181 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); 6182 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6183 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6184 PetscCall(VecGetArrayRead(v, &vArray)); 6185 /* Get values */ 6186 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6187 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6188 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6189 /* Cleanup array */ 6190 PetscCall(VecRestoreArrayRead(v, &vArray)); 6191 } 6192 if (csize) *csize = asize; 6193 /* Cleanup points */ 6194 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6195 PetscFunctionReturn(PETSC_SUCCESS); 6196 } 6197 6198 /*@C 6199 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6200 6201 Not collective 6202 6203 Input Parameters: 6204 + dm - The `DM` 6205 . section - The section describing the layout in `v`, or `NULL` to use the default section 6206 . v - The local vector 6207 - point - The point in the `DM` 6208 6209 Input/Output Parameters: 6210 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6211 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6212 if the user provided `NULL`, it is a borrowed array and should not be freed 6213 6214 Level: intermediate 6215 6216 Notes: 6217 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6218 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6219 assembly function, and a user may already have allocated storage for this operation. 6220 6221 A typical use could be 6222 .vb 6223 values = NULL; 6224 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6225 for (cl = 0; cl < clSize; ++cl) { 6226 <Compute on closure> 6227 } 6228 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6229 .ve 6230 or 6231 .vb 6232 PetscMalloc1(clMaxSize, &values); 6233 for (p = pStart; p < pEnd; ++p) { 6234 clSize = clMaxSize; 6235 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6236 for (cl = 0; cl < clSize; ++cl) { 6237 <Compute on closure> 6238 } 6239 } 6240 PetscFree(values); 6241 .ve 6242 6243 Fortran Notes: 6244 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6245 6246 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6247 @*/ 6248 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6249 { 6250 PetscFunctionBeginHot; 6251 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6252 PetscFunctionReturn(PETSC_SUCCESS); 6253 } 6254 6255 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6256 { 6257 DMLabel depthLabel; 6258 PetscSection clSection; 6259 IS clPoints; 6260 PetscScalar *array; 6261 const PetscScalar *vArray; 6262 PetscInt *points = NULL; 6263 const PetscInt *clp, *perm = NULL; 6264 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6265 6266 PetscFunctionBeginHot; 6267 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6268 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6269 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6270 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6271 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6272 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6273 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6274 if (mdepth == 1 && numFields < 2) { 6275 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6276 PetscFunctionReturn(PETSC_SUCCESS); 6277 } 6278 /* Get points */ 6279 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6280 for (clsize = 0, p = 0; p < Np; p++) { 6281 PetscInt dof; 6282 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6283 clsize += dof; 6284 } 6285 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6286 /* Filter points */ 6287 for (p = 0; p < numPoints * 2; p += 2) { 6288 PetscInt dep; 6289 6290 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6291 if (dep != depth) continue; 6292 points[Np * 2 + 0] = points[p]; 6293 points[Np * 2 + 1] = points[p + 1]; 6294 ++Np; 6295 } 6296 /* Get array */ 6297 if (!values || !*values) { 6298 PetscInt asize = 0, dof; 6299 6300 for (p = 0; p < Np * 2; p += 2) { 6301 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6302 asize += dof; 6303 } 6304 if (!values) { 6305 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6306 if (csize) *csize = asize; 6307 PetscFunctionReturn(PETSC_SUCCESS); 6308 } 6309 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6310 } else { 6311 array = *values; 6312 } 6313 PetscCall(VecGetArrayRead(v, &vArray)); 6314 /* Get values */ 6315 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6316 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6317 /* Cleanup points */ 6318 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6319 /* Cleanup array */ 6320 PetscCall(VecRestoreArrayRead(v, &vArray)); 6321 if (!*values) { 6322 if (csize) *csize = size; 6323 *values = array; 6324 } else { 6325 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6326 *csize = size; 6327 } 6328 PetscFunctionReturn(PETSC_SUCCESS); 6329 } 6330 6331 /*@C 6332 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6333 6334 Not collective 6335 6336 Input Parameters: 6337 + dm - The `DM` 6338 . section - The section describing the layout in `v`, or `NULL` to use the default section 6339 . v - The local vector 6340 . point - The point in the `DM` 6341 . csize - The number of values in the closure, or `NULL` 6342 - values - The array of values, which is a borrowed array and should not be freed 6343 6344 Level: intermediate 6345 6346 Note: 6347 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6348 6349 Fortran Notes: 6350 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6351 6352 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6353 @*/ 6354 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6355 { 6356 PetscInt size = 0; 6357 6358 PetscFunctionBegin; 6359 /* Should work without recalculating size */ 6360 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6361 *values = NULL; 6362 PetscFunctionReturn(PETSC_SUCCESS); 6363 } 6364 6365 static inline void add(PetscScalar *x, PetscScalar y) 6366 { 6367 *x += y; 6368 } 6369 static inline void insert(PetscScalar *x, PetscScalar y) 6370 { 6371 *x = y; 6372 } 6373 6374 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[]) 6375 { 6376 PetscInt cdof; /* The number of constraints on this point */ 6377 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6378 PetscScalar *a; 6379 PetscInt off, cind = 0, k; 6380 6381 PetscFunctionBegin; 6382 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6383 PetscCall(PetscSectionGetOffset(section, point, &off)); 6384 a = &array[off]; 6385 if (!cdof || setBC) { 6386 if (clperm) { 6387 if (perm) { 6388 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6389 } else { 6390 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6391 } 6392 } else { 6393 if (perm) { 6394 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6395 } else { 6396 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6397 } 6398 } 6399 } else { 6400 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6401 if (clperm) { 6402 if (perm) { 6403 for (k = 0; k < dof; ++k) { 6404 if ((cind < cdof) && (k == cdofs[cind])) { 6405 ++cind; 6406 continue; 6407 } 6408 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6409 } 6410 } else { 6411 for (k = 0; k < dof; ++k) { 6412 if ((cind < cdof) && (k == cdofs[cind])) { 6413 ++cind; 6414 continue; 6415 } 6416 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6417 } 6418 } 6419 } else { 6420 if (perm) { 6421 for (k = 0; k < dof; ++k) { 6422 if ((cind < cdof) && (k == cdofs[cind])) { 6423 ++cind; 6424 continue; 6425 } 6426 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6427 } 6428 } else { 6429 for (k = 0; k < dof; ++k) { 6430 if ((cind < cdof) && (k == cdofs[cind])) { 6431 ++cind; 6432 continue; 6433 } 6434 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6435 } 6436 } 6437 } 6438 } 6439 PetscFunctionReturn(PETSC_SUCCESS); 6440 } 6441 6442 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[]) 6443 { 6444 PetscInt cdof; /* The number of constraints on this point */ 6445 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6446 PetscScalar *a; 6447 PetscInt off, cind = 0, k; 6448 6449 PetscFunctionBegin; 6450 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6451 PetscCall(PetscSectionGetOffset(section, point, &off)); 6452 a = &array[off]; 6453 if (cdof) { 6454 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6455 if (clperm) { 6456 if (perm) { 6457 for (k = 0; k < dof; ++k) { 6458 if ((cind < cdof) && (k == cdofs[cind])) { 6459 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6460 cind++; 6461 } 6462 } 6463 } else { 6464 for (k = 0; k < dof; ++k) { 6465 if ((cind < cdof) && (k == cdofs[cind])) { 6466 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6467 cind++; 6468 } 6469 } 6470 } 6471 } else { 6472 if (perm) { 6473 for (k = 0; k < dof; ++k) { 6474 if ((cind < cdof) && (k == cdofs[cind])) { 6475 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6476 cind++; 6477 } 6478 } 6479 } else { 6480 for (k = 0; k < dof; ++k) { 6481 if ((cind < cdof) && (k == cdofs[cind])) { 6482 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6483 cind++; 6484 } 6485 } 6486 } 6487 } 6488 } 6489 PetscFunctionReturn(PETSC_SUCCESS); 6490 } 6491 6492 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[]) 6493 { 6494 PetscScalar *a; 6495 PetscInt fdof, foff, fcdof, foffset = *offset; 6496 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6497 PetscInt cind = 0, b; 6498 6499 PetscFunctionBegin; 6500 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6501 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6502 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6503 a = &array[foff]; 6504 if (!fcdof || setBC) { 6505 if (clperm) { 6506 if (perm) { 6507 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6508 } else { 6509 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6510 } 6511 } else { 6512 if (perm) { 6513 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6514 } else { 6515 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6516 } 6517 } 6518 } else { 6519 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6520 if (clperm) { 6521 if (perm) { 6522 for (b = 0; b < fdof; b++) { 6523 if ((cind < fcdof) && (b == fcdofs[cind])) { 6524 ++cind; 6525 continue; 6526 } 6527 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6528 } 6529 } else { 6530 for (b = 0; b < fdof; b++) { 6531 if ((cind < fcdof) && (b == fcdofs[cind])) { 6532 ++cind; 6533 continue; 6534 } 6535 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6536 } 6537 } 6538 } else { 6539 if (perm) { 6540 for (b = 0; b < fdof; b++) { 6541 if ((cind < fcdof) && (b == fcdofs[cind])) { 6542 ++cind; 6543 continue; 6544 } 6545 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6546 } 6547 } else { 6548 for (b = 0; b < fdof; b++) { 6549 if ((cind < fcdof) && (b == fcdofs[cind])) { 6550 ++cind; 6551 continue; 6552 } 6553 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6554 } 6555 } 6556 } 6557 } 6558 *offset += fdof; 6559 PetscFunctionReturn(PETSC_SUCCESS); 6560 } 6561 6562 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[]) 6563 { 6564 PetscScalar *a; 6565 PetscInt fdof, foff, fcdof, foffset = *offset; 6566 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6567 PetscInt Nc, cind = 0, ncind = 0, b; 6568 PetscBool ncSet, fcSet; 6569 6570 PetscFunctionBegin; 6571 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6572 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6573 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6574 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6575 a = &array[foff]; 6576 if (fcdof) { 6577 /* We just override fcdof and fcdofs with Ncc and comps */ 6578 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6579 if (clperm) { 6580 if (perm) { 6581 if (comps) { 6582 for (b = 0; b < fdof; b++) { 6583 ncSet = fcSet = PETSC_FALSE; 6584 if (b % Nc == comps[ncind]) { 6585 ncind = (ncind + 1) % Ncc; 6586 ncSet = PETSC_TRUE; 6587 } 6588 if ((cind < fcdof) && (b == fcdofs[cind])) { 6589 ++cind; 6590 fcSet = PETSC_TRUE; 6591 } 6592 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6593 } 6594 } else { 6595 for (b = 0; b < fdof; b++) { 6596 if ((cind < fcdof) && (b == fcdofs[cind])) { 6597 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6598 ++cind; 6599 } 6600 } 6601 } 6602 } else { 6603 if (comps) { 6604 for (b = 0; b < fdof; b++) { 6605 ncSet = fcSet = PETSC_FALSE; 6606 if (b % Nc == comps[ncind]) { 6607 ncind = (ncind + 1) % Ncc; 6608 ncSet = PETSC_TRUE; 6609 } 6610 if ((cind < fcdof) && (b == fcdofs[cind])) { 6611 ++cind; 6612 fcSet = PETSC_TRUE; 6613 } 6614 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6615 } 6616 } else { 6617 for (b = 0; b < fdof; b++) { 6618 if ((cind < fcdof) && (b == fcdofs[cind])) { 6619 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6620 ++cind; 6621 } 6622 } 6623 } 6624 } 6625 } else { 6626 if (perm) { 6627 if (comps) { 6628 for (b = 0; b < fdof; b++) { 6629 ncSet = fcSet = PETSC_FALSE; 6630 if (b % Nc == comps[ncind]) { 6631 ncind = (ncind + 1) % Ncc; 6632 ncSet = PETSC_TRUE; 6633 } 6634 if ((cind < fcdof) && (b == fcdofs[cind])) { 6635 ++cind; 6636 fcSet = PETSC_TRUE; 6637 } 6638 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6639 } 6640 } else { 6641 for (b = 0; b < fdof; b++) { 6642 if ((cind < fcdof) && (b == fcdofs[cind])) { 6643 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6644 ++cind; 6645 } 6646 } 6647 } 6648 } else { 6649 if (comps) { 6650 for (b = 0; b < fdof; b++) { 6651 ncSet = fcSet = PETSC_FALSE; 6652 if (b % Nc == comps[ncind]) { 6653 ncind = (ncind + 1) % Ncc; 6654 ncSet = PETSC_TRUE; 6655 } 6656 if ((cind < fcdof) && (b == fcdofs[cind])) { 6657 ++cind; 6658 fcSet = PETSC_TRUE; 6659 } 6660 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6661 } 6662 } else { 6663 for (b = 0; b < fdof; b++) { 6664 if ((cind < fcdof) && (b == fcdofs[cind])) { 6665 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6666 ++cind; 6667 } 6668 } 6669 } 6670 } 6671 } 6672 } 6673 *offset += fdof; 6674 PetscFunctionReturn(PETSC_SUCCESS); 6675 } 6676 6677 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6678 { 6679 PetscScalar *array; 6680 const PetscInt *cone, *coneO; 6681 PetscInt pStart, pEnd, p, numPoints, off, dof; 6682 6683 PetscFunctionBeginHot; 6684 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6685 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6686 PetscCall(DMPlexGetCone(dm, point, &cone)); 6687 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6688 PetscCall(VecGetArray(v, &array)); 6689 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6690 const PetscInt cp = !p ? point : cone[p - 1]; 6691 const PetscInt o = !p ? 0 : coneO[p - 1]; 6692 6693 if ((cp < pStart) || (cp >= pEnd)) { 6694 dof = 0; 6695 continue; 6696 } 6697 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6698 /* ADD_VALUES */ 6699 { 6700 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6701 PetscScalar *a; 6702 PetscInt cdof, coff, cind = 0, k; 6703 6704 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6705 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6706 a = &array[coff]; 6707 if (!cdof) { 6708 if (o >= 0) { 6709 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6710 } else { 6711 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6712 } 6713 } else { 6714 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6715 if (o >= 0) { 6716 for (k = 0; k < dof; ++k) { 6717 if ((cind < cdof) && (k == cdofs[cind])) { 6718 ++cind; 6719 continue; 6720 } 6721 a[k] += values[off + k]; 6722 } 6723 } else { 6724 for (k = 0; k < dof; ++k) { 6725 if ((cind < cdof) && (k == cdofs[cind])) { 6726 ++cind; 6727 continue; 6728 } 6729 a[k] += values[off + dof - k - 1]; 6730 } 6731 } 6732 } 6733 } 6734 } 6735 PetscCall(VecRestoreArray(v, &array)); 6736 PetscFunctionReturn(PETSC_SUCCESS); 6737 } 6738 6739 /*@C 6740 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6741 6742 Not collective 6743 6744 Input Parameters: 6745 + dm - The `DM` 6746 . section - The section describing the layout in `v`, or `NULL` to use the default section 6747 . v - The local vector 6748 . point - The point in the `DM` 6749 . values - The array of values 6750 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6751 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6752 6753 Level: intermediate 6754 6755 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6756 @*/ 6757 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6758 { 6759 PetscSection clSection; 6760 IS clPoints; 6761 PetscScalar *array; 6762 PetscInt *points = NULL; 6763 const PetscInt *clp, *clperm = NULL; 6764 PetscInt depth, numFields, numPoints, p, clsize; 6765 6766 PetscFunctionBeginHot; 6767 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6768 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6769 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6770 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6771 PetscCall(DMPlexGetDepth(dm, &depth)); 6772 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6773 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6774 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6775 PetscFunctionReturn(PETSC_SUCCESS); 6776 } 6777 /* Get points */ 6778 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6779 for (clsize = 0, p = 0; p < numPoints; p++) { 6780 PetscInt dof; 6781 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6782 clsize += dof; 6783 } 6784 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6785 /* Get array */ 6786 PetscCall(VecGetArray(v, &array)); 6787 /* Get values */ 6788 if (numFields > 0) { 6789 PetscInt offset = 0, f; 6790 for (f = 0; f < numFields; ++f) { 6791 const PetscInt **perms = NULL; 6792 const PetscScalar **flips = NULL; 6793 6794 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6795 switch (mode) { 6796 case INSERT_VALUES: 6797 for (p = 0; p < numPoints; p++) { 6798 const PetscInt point = points[2 * p]; 6799 const PetscInt *perm = perms ? perms[p] : NULL; 6800 const PetscScalar *flip = flips ? flips[p] : NULL; 6801 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6802 } 6803 break; 6804 case INSERT_ALL_VALUES: 6805 for (p = 0; p < numPoints; p++) { 6806 const PetscInt point = points[2 * p]; 6807 const PetscInt *perm = perms ? perms[p] : NULL; 6808 const PetscScalar *flip = flips ? flips[p] : NULL; 6809 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6810 } 6811 break; 6812 case INSERT_BC_VALUES: 6813 for (p = 0; p < numPoints; p++) { 6814 const PetscInt point = points[2 * p]; 6815 const PetscInt *perm = perms ? perms[p] : NULL; 6816 const PetscScalar *flip = flips ? flips[p] : NULL; 6817 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6818 } 6819 break; 6820 case ADD_VALUES: 6821 for (p = 0; p < numPoints; p++) { 6822 const PetscInt point = points[2 * p]; 6823 const PetscInt *perm = perms ? perms[p] : NULL; 6824 const PetscScalar *flip = flips ? flips[p] : NULL; 6825 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6826 } 6827 break; 6828 case ADD_ALL_VALUES: 6829 for (p = 0; p < numPoints; p++) { 6830 const PetscInt point = points[2 * p]; 6831 const PetscInt *perm = perms ? perms[p] : NULL; 6832 const PetscScalar *flip = flips ? flips[p] : NULL; 6833 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6834 } 6835 break; 6836 case ADD_BC_VALUES: 6837 for (p = 0; p < numPoints; p++) { 6838 const PetscInt point = points[2 * p]; 6839 const PetscInt *perm = perms ? perms[p] : NULL; 6840 const PetscScalar *flip = flips ? flips[p] : NULL; 6841 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6842 } 6843 break; 6844 default: 6845 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6846 } 6847 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6848 } 6849 } else { 6850 PetscInt dof, off; 6851 const PetscInt **perms = NULL; 6852 const PetscScalar **flips = NULL; 6853 6854 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6855 switch (mode) { 6856 case INSERT_VALUES: 6857 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6858 const PetscInt point = points[2 * p]; 6859 const PetscInt *perm = perms ? perms[p] : NULL; 6860 const PetscScalar *flip = flips ? flips[p] : NULL; 6861 PetscCall(PetscSectionGetDof(section, point, &dof)); 6862 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6863 } 6864 break; 6865 case INSERT_ALL_VALUES: 6866 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6867 const PetscInt point = points[2 * p]; 6868 const PetscInt *perm = perms ? perms[p] : NULL; 6869 const PetscScalar *flip = flips ? flips[p] : NULL; 6870 PetscCall(PetscSectionGetDof(section, point, &dof)); 6871 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6872 } 6873 break; 6874 case INSERT_BC_VALUES: 6875 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6876 const PetscInt point = points[2 * p]; 6877 const PetscInt *perm = perms ? perms[p] : NULL; 6878 const PetscScalar *flip = flips ? flips[p] : NULL; 6879 PetscCall(PetscSectionGetDof(section, point, &dof)); 6880 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6881 } 6882 break; 6883 case ADD_VALUES: 6884 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6885 const PetscInt point = points[2 * p]; 6886 const PetscInt *perm = perms ? perms[p] : NULL; 6887 const PetscScalar *flip = flips ? flips[p] : NULL; 6888 PetscCall(PetscSectionGetDof(section, point, &dof)); 6889 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6890 } 6891 break; 6892 case ADD_ALL_VALUES: 6893 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6894 const PetscInt point = points[2 * p]; 6895 const PetscInt *perm = perms ? perms[p] : NULL; 6896 const PetscScalar *flip = flips ? flips[p] : NULL; 6897 PetscCall(PetscSectionGetDof(section, point, &dof)); 6898 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6899 } 6900 break; 6901 case ADD_BC_VALUES: 6902 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6903 const PetscInt point = points[2 * p]; 6904 const PetscInt *perm = perms ? perms[p] : NULL; 6905 const PetscScalar *flip = flips ? flips[p] : NULL; 6906 PetscCall(PetscSectionGetDof(section, point, &dof)); 6907 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6908 } 6909 break; 6910 default: 6911 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6912 } 6913 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6914 } 6915 /* Cleanup points */ 6916 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6917 /* Cleanup array */ 6918 PetscCall(VecRestoreArray(v, &array)); 6919 PetscFunctionReturn(PETSC_SUCCESS); 6920 } 6921 6922 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6923 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6924 { 6925 PetscFunctionBegin; 6926 *contains = PETSC_TRUE; 6927 if (label) { 6928 PetscInt fdof; 6929 6930 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6931 if (!*contains) { 6932 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6933 *offset += fdof; 6934 PetscFunctionReturn(PETSC_SUCCESS); 6935 } 6936 } 6937 PetscFunctionReturn(PETSC_SUCCESS); 6938 } 6939 6940 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6941 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) 6942 { 6943 PetscSection clSection; 6944 IS clPoints; 6945 PetscScalar *array; 6946 PetscInt *points = NULL; 6947 const PetscInt *clp; 6948 PetscInt numFields, numPoints, p; 6949 PetscInt offset = 0, f; 6950 6951 PetscFunctionBeginHot; 6952 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6953 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6954 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6955 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6956 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6957 /* Get points */ 6958 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6959 /* Get array */ 6960 PetscCall(VecGetArray(v, &array)); 6961 /* Get values */ 6962 for (f = 0; f < numFields; ++f) { 6963 const PetscInt **perms = NULL; 6964 const PetscScalar **flips = NULL; 6965 PetscBool contains; 6966 6967 if (!fieldActive[f]) { 6968 for (p = 0; p < numPoints * 2; p += 2) { 6969 PetscInt fdof; 6970 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6971 offset += fdof; 6972 } 6973 continue; 6974 } 6975 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6976 switch (mode) { 6977 case INSERT_VALUES: 6978 for (p = 0; p < numPoints; p++) { 6979 const PetscInt point = points[2 * p]; 6980 const PetscInt *perm = perms ? perms[p] : NULL; 6981 const PetscScalar *flip = flips ? flips[p] : NULL; 6982 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6983 if (!contains) continue; 6984 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6985 } 6986 break; 6987 case INSERT_ALL_VALUES: 6988 for (p = 0; p < numPoints; p++) { 6989 const PetscInt point = points[2 * p]; 6990 const PetscInt *perm = perms ? perms[p] : NULL; 6991 const PetscScalar *flip = flips ? flips[p] : NULL; 6992 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6993 if (!contains) continue; 6994 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6995 } 6996 break; 6997 case INSERT_BC_VALUES: 6998 for (p = 0; p < numPoints; p++) { 6999 const PetscInt point = points[2 * p]; 7000 const PetscInt *perm = perms ? perms[p] : NULL; 7001 const PetscScalar *flip = flips ? flips[p] : NULL; 7002 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7003 if (!contains) continue; 7004 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7005 } 7006 break; 7007 case ADD_VALUES: 7008 for (p = 0; p < numPoints; p++) { 7009 const PetscInt point = points[2 * p]; 7010 const PetscInt *perm = perms ? perms[p] : NULL; 7011 const PetscScalar *flip = flips ? flips[p] : NULL; 7012 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7013 if (!contains) continue; 7014 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7015 } 7016 break; 7017 case ADD_ALL_VALUES: 7018 for (p = 0; p < numPoints; p++) { 7019 const PetscInt point = points[2 * p]; 7020 const PetscInt *perm = perms ? perms[p] : NULL; 7021 const PetscScalar *flip = flips ? flips[p] : NULL; 7022 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7023 if (!contains) continue; 7024 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7025 } 7026 break; 7027 default: 7028 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7029 } 7030 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7031 } 7032 /* Cleanup points */ 7033 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7034 /* Cleanup array */ 7035 PetscCall(VecRestoreArray(v, &array)); 7036 PetscFunctionReturn(PETSC_SUCCESS); 7037 } 7038 7039 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7040 { 7041 PetscMPIInt rank; 7042 PetscInt i, j; 7043 7044 PetscFunctionBegin; 7045 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7046 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7047 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7048 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7049 numCIndices = numCIndices ? numCIndices : numRIndices; 7050 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7051 for (i = 0; i < numRIndices; i++) { 7052 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7053 for (j = 0; j < numCIndices; j++) { 7054 #if defined(PETSC_USE_COMPLEX) 7055 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7056 #else 7057 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7058 #endif 7059 } 7060 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7061 } 7062 PetscFunctionReturn(PETSC_SUCCESS); 7063 } 7064 7065 /* 7066 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7067 7068 Input Parameters: 7069 + section - The section for this data layout 7070 . islocal - Is the section (and thus indices being requested) local or global? 7071 . point - The point contributing dofs with these indices 7072 . off - The global offset of this point 7073 . loff - The local offset of each field 7074 . setBC - The flag determining whether to include indices of boundary values 7075 . perm - A permutation of the dofs on this point, or NULL 7076 - indperm - A permutation of the entire indices array, or NULL 7077 7078 Output Parameter: 7079 . indices - Indices for dofs on this point 7080 7081 Level: developer 7082 7083 Note: The indices could be local or global, depending on the value of 'off'. 7084 */ 7085 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7086 { 7087 PetscInt dof; /* The number of unknowns on this point */ 7088 PetscInt cdof; /* The number of constraints on this point */ 7089 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7090 PetscInt cind = 0, k; 7091 7092 PetscFunctionBegin; 7093 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7094 PetscCall(PetscSectionGetDof(section, point, &dof)); 7095 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7096 if (!cdof || setBC) { 7097 for (k = 0; k < dof; ++k) { 7098 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7099 const PetscInt ind = indperm ? indperm[preind] : preind; 7100 7101 indices[ind] = off + k; 7102 } 7103 } else { 7104 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7105 for (k = 0; k < dof; ++k) { 7106 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7107 const PetscInt ind = indperm ? indperm[preind] : preind; 7108 7109 if ((cind < cdof) && (k == cdofs[cind])) { 7110 /* Insert check for returning constrained indices */ 7111 indices[ind] = -(off + k + 1); 7112 ++cind; 7113 } else { 7114 indices[ind] = off + k - (islocal ? 0 : cind); 7115 } 7116 } 7117 } 7118 *loff += dof; 7119 PetscFunctionReturn(PETSC_SUCCESS); 7120 } 7121 7122 /* 7123 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7124 7125 Input Parameters: 7126 + section - a section (global or local) 7127 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7128 . point - point within section 7129 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7130 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7131 . setBC - identify constrained (boundary condition) points via involution. 7132 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7133 . permsoff - offset 7134 - indperm - index permutation 7135 7136 Output Parameter: 7137 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7138 . indices - array to hold indices (as defined by section) of each dof associated with point 7139 7140 Notes: 7141 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7142 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7143 in the local vector. 7144 7145 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7146 significant). It is invalid to call with a global section and setBC=true. 7147 7148 Developer Note: 7149 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7150 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7151 offset could be obtained from the section instead of passing it explicitly as we do now. 7152 7153 Example: 7154 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7155 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7156 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7157 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. 7158 7159 Level: developer 7160 */ 7161 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[]) 7162 { 7163 PetscInt numFields, foff, f; 7164 7165 PetscFunctionBegin; 7166 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7167 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7168 for (f = 0, foff = 0; f < numFields; ++f) { 7169 PetscInt fdof, cfdof; 7170 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7171 PetscInt cind = 0, b; 7172 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7173 7174 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7175 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7176 if (!cfdof || setBC) { 7177 for (b = 0; b < fdof; ++b) { 7178 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7179 const PetscInt ind = indperm ? indperm[preind] : preind; 7180 7181 indices[ind] = off + foff + b; 7182 } 7183 } else { 7184 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7185 for (b = 0; b < fdof; ++b) { 7186 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7187 const PetscInt ind = indperm ? indperm[preind] : preind; 7188 7189 if ((cind < cfdof) && (b == fcdofs[cind])) { 7190 indices[ind] = -(off + foff + b + 1); 7191 ++cind; 7192 } else { 7193 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7194 } 7195 } 7196 } 7197 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7198 foffs[f] += fdof; 7199 } 7200 PetscFunctionReturn(PETSC_SUCCESS); 7201 } 7202 7203 /* 7204 This version believes the globalSection offsets for each field, rather than just the point offset 7205 7206 . foffs - The offset into 'indices' for each field, since it is segregated by field 7207 7208 Notes: 7209 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7210 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7211 */ 7212 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7213 { 7214 PetscInt numFields, foff, f; 7215 7216 PetscFunctionBegin; 7217 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7218 for (f = 0; f < numFields; ++f) { 7219 PetscInt fdof, cfdof; 7220 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7221 PetscInt cind = 0, b; 7222 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7223 7224 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7225 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7226 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7227 if (!cfdof) { 7228 for (b = 0; b < fdof; ++b) { 7229 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7230 const PetscInt ind = indperm ? indperm[preind] : preind; 7231 7232 indices[ind] = foff + b; 7233 } 7234 } else { 7235 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7236 for (b = 0; b < fdof; ++b) { 7237 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7238 const PetscInt ind = indperm ? indperm[preind] : preind; 7239 7240 if ((cind < cfdof) && (b == fcdofs[cind])) { 7241 indices[ind] = -(foff + b + 1); 7242 ++cind; 7243 } else { 7244 indices[ind] = foff + b - cind; 7245 } 7246 } 7247 } 7248 foffs[f] += fdof; 7249 } 7250 PetscFunctionReturn(PETSC_SUCCESS); 7251 } 7252 7253 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) 7254 { 7255 Mat cMat; 7256 PetscSection aSec, cSec; 7257 IS aIS; 7258 PetscInt aStart = -1, aEnd = -1; 7259 const PetscInt *anchors; 7260 PetscInt numFields, f, p, q, newP = 0; 7261 PetscInt newNumPoints = 0, newNumIndices = 0; 7262 PetscInt *newPoints, *indices, *newIndices; 7263 PetscInt maxAnchor, maxDof; 7264 PetscInt newOffsets[32]; 7265 PetscInt *pointMatOffsets[32]; 7266 PetscInt *newPointOffsets[32]; 7267 PetscScalar *pointMat[32]; 7268 PetscScalar *newValues = NULL, *tmpValues; 7269 PetscBool anyConstrained = PETSC_FALSE; 7270 7271 PetscFunctionBegin; 7272 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7273 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7274 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7275 7276 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7277 /* if there are point-to-point constraints */ 7278 if (aSec) { 7279 PetscCall(PetscArrayzero(newOffsets, 32)); 7280 PetscCall(ISGetIndices(aIS, &anchors)); 7281 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7282 /* figure out how many points are going to be in the new element matrix 7283 * (we allow double counting, because it's all just going to be summed 7284 * into the global matrix anyway) */ 7285 for (p = 0; p < 2 * numPoints; p += 2) { 7286 PetscInt b = points[p]; 7287 PetscInt bDof = 0, bSecDof; 7288 7289 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7290 if (!bSecDof) continue; 7291 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7292 if (bDof) { 7293 /* this point is constrained */ 7294 /* it is going to be replaced by its anchors */ 7295 PetscInt bOff, q; 7296 7297 anyConstrained = PETSC_TRUE; 7298 newNumPoints += bDof; 7299 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7300 for (q = 0; q < bDof; q++) { 7301 PetscInt a = anchors[bOff + q]; 7302 PetscInt aDof; 7303 7304 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7305 newNumIndices += aDof; 7306 for (f = 0; f < numFields; ++f) { 7307 PetscInt fDof; 7308 7309 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7310 newOffsets[f + 1] += fDof; 7311 } 7312 } 7313 } else { 7314 /* this point is not constrained */ 7315 newNumPoints++; 7316 newNumIndices += bSecDof; 7317 for (f = 0; f < numFields; ++f) { 7318 PetscInt fDof; 7319 7320 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7321 newOffsets[f + 1] += fDof; 7322 } 7323 } 7324 } 7325 } 7326 if (!anyConstrained) { 7327 if (outNumPoints) *outNumPoints = 0; 7328 if (outNumIndices) *outNumIndices = 0; 7329 if (outPoints) *outPoints = NULL; 7330 if (outValues) *outValues = NULL; 7331 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7332 PetscFunctionReturn(PETSC_SUCCESS); 7333 } 7334 7335 if (outNumPoints) *outNumPoints = newNumPoints; 7336 if (outNumIndices) *outNumIndices = newNumIndices; 7337 7338 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7339 7340 if (!outPoints && !outValues) { 7341 if (offsets) { 7342 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7343 } 7344 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7345 PetscFunctionReturn(PETSC_SUCCESS); 7346 } 7347 7348 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7349 7350 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7351 7352 /* workspaces */ 7353 if (numFields) { 7354 for (f = 0; f < numFields; f++) { 7355 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7356 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7357 } 7358 } else { 7359 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7360 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7361 } 7362 7363 /* get workspaces for the point-to-point matrices */ 7364 if (numFields) { 7365 PetscInt totalOffset, totalMatOffset; 7366 7367 for (p = 0; p < numPoints; p++) { 7368 PetscInt b = points[2 * p]; 7369 PetscInt bDof = 0, bSecDof; 7370 7371 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7372 if (!bSecDof) { 7373 for (f = 0; f < numFields; f++) { 7374 newPointOffsets[f][p + 1] = 0; 7375 pointMatOffsets[f][p + 1] = 0; 7376 } 7377 continue; 7378 } 7379 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7380 if (bDof) { 7381 for (f = 0; f < numFields; f++) { 7382 PetscInt fDof, q, bOff, allFDof = 0; 7383 7384 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7385 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7386 for (q = 0; q < bDof; q++) { 7387 PetscInt a = anchors[bOff + q]; 7388 PetscInt aFDof; 7389 7390 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7391 allFDof += aFDof; 7392 } 7393 newPointOffsets[f][p + 1] = allFDof; 7394 pointMatOffsets[f][p + 1] = fDof * allFDof; 7395 } 7396 } else { 7397 for (f = 0; f < numFields; f++) { 7398 PetscInt fDof; 7399 7400 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7401 newPointOffsets[f][p + 1] = fDof; 7402 pointMatOffsets[f][p + 1] = 0; 7403 } 7404 } 7405 } 7406 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7407 newPointOffsets[f][0] = totalOffset; 7408 pointMatOffsets[f][0] = totalMatOffset; 7409 for (p = 0; p < numPoints; p++) { 7410 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7411 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7412 } 7413 totalOffset = newPointOffsets[f][numPoints]; 7414 totalMatOffset = pointMatOffsets[f][numPoints]; 7415 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7416 } 7417 } else { 7418 for (p = 0; p < numPoints; p++) { 7419 PetscInt b = points[2 * p]; 7420 PetscInt bDof = 0, bSecDof; 7421 7422 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7423 if (!bSecDof) { 7424 newPointOffsets[0][p + 1] = 0; 7425 pointMatOffsets[0][p + 1] = 0; 7426 continue; 7427 } 7428 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7429 if (bDof) { 7430 PetscInt bOff, q, allDof = 0; 7431 7432 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7433 for (q = 0; q < bDof; q++) { 7434 PetscInt a = anchors[bOff + q], aDof; 7435 7436 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7437 allDof += aDof; 7438 } 7439 newPointOffsets[0][p + 1] = allDof; 7440 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7441 } else { 7442 newPointOffsets[0][p + 1] = bSecDof; 7443 pointMatOffsets[0][p + 1] = 0; 7444 } 7445 } 7446 newPointOffsets[0][0] = 0; 7447 pointMatOffsets[0][0] = 0; 7448 for (p = 0; p < numPoints; p++) { 7449 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7450 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7451 } 7452 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7453 } 7454 7455 /* output arrays */ 7456 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7457 7458 /* get the point-to-point matrices; construct newPoints */ 7459 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7460 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7461 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7462 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7463 if (numFields) { 7464 for (p = 0, newP = 0; p < numPoints; p++) { 7465 PetscInt b = points[2 * p]; 7466 PetscInt o = points[2 * p + 1]; 7467 PetscInt bDof = 0, bSecDof; 7468 7469 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7470 if (!bSecDof) continue; 7471 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7472 if (bDof) { 7473 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7474 7475 fStart[0] = 0; 7476 fEnd[0] = 0; 7477 for (f = 0; f < numFields; f++) { 7478 PetscInt fDof; 7479 7480 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7481 fStart[f + 1] = fStart[f] + fDof; 7482 fEnd[f + 1] = fStart[f + 1]; 7483 } 7484 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7485 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7486 7487 fAnchorStart[0] = 0; 7488 fAnchorEnd[0] = 0; 7489 for (f = 0; f < numFields; f++) { 7490 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7491 7492 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7493 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7494 } 7495 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7496 for (q = 0; q < bDof; q++) { 7497 PetscInt a = anchors[bOff + q], aOff; 7498 7499 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7500 newPoints[2 * (newP + q)] = a; 7501 newPoints[2 * (newP + q) + 1] = 0; 7502 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7503 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7504 } 7505 newP += bDof; 7506 7507 if (outValues) { 7508 /* get the point-to-point submatrix */ 7509 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])); 7510 } 7511 } else { 7512 newPoints[2 * newP] = b; 7513 newPoints[2 * newP + 1] = o; 7514 newP++; 7515 } 7516 } 7517 } else { 7518 for (p = 0; p < numPoints; p++) { 7519 PetscInt b = points[2 * p]; 7520 PetscInt o = points[2 * p + 1]; 7521 PetscInt bDof = 0, bSecDof; 7522 7523 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7524 if (!bSecDof) continue; 7525 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7526 if (bDof) { 7527 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7528 7529 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7530 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7531 7532 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7533 for (q = 0; q < bDof; q++) { 7534 PetscInt a = anchors[bOff + q], aOff; 7535 7536 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7537 7538 newPoints[2 * (newP + q)] = a; 7539 newPoints[2 * (newP + q) + 1] = 0; 7540 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7541 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7542 } 7543 newP += bDof; 7544 7545 /* get the point-to-point submatrix */ 7546 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7547 } else { 7548 newPoints[2 * newP] = b; 7549 newPoints[2 * newP + 1] = o; 7550 newP++; 7551 } 7552 } 7553 } 7554 7555 if (outValues) { 7556 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7557 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7558 /* multiply constraints on the right */ 7559 if (numFields) { 7560 for (f = 0; f < numFields; f++) { 7561 PetscInt oldOff = offsets[f]; 7562 7563 for (p = 0; p < numPoints; p++) { 7564 PetscInt cStart = newPointOffsets[f][p]; 7565 PetscInt b = points[2 * p]; 7566 PetscInt c, r, k; 7567 PetscInt dof; 7568 7569 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7570 if (!dof) continue; 7571 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7572 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7573 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7574 7575 for (r = 0; r < numIndices; r++) { 7576 for (c = 0; c < nCols; c++) { 7577 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7578 } 7579 } 7580 } else { 7581 /* copy this column as is */ 7582 for (r = 0; r < numIndices; r++) { 7583 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7584 } 7585 } 7586 oldOff += dof; 7587 } 7588 } 7589 } else { 7590 PetscInt oldOff = 0; 7591 for (p = 0; p < numPoints; p++) { 7592 PetscInt cStart = newPointOffsets[0][p]; 7593 PetscInt b = points[2 * p]; 7594 PetscInt c, r, k; 7595 PetscInt dof; 7596 7597 PetscCall(PetscSectionGetDof(section, b, &dof)); 7598 if (!dof) continue; 7599 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7600 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7601 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7602 7603 for (r = 0; r < numIndices; r++) { 7604 for (c = 0; c < nCols; c++) { 7605 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7606 } 7607 } 7608 } else { 7609 /* copy this column as is */ 7610 for (r = 0; r < numIndices; r++) { 7611 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7612 } 7613 } 7614 oldOff += dof; 7615 } 7616 } 7617 7618 if (multiplyLeft) { 7619 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7620 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7621 /* multiply constraints transpose on the left */ 7622 if (numFields) { 7623 for (f = 0; f < numFields; f++) { 7624 PetscInt oldOff = offsets[f]; 7625 7626 for (p = 0; p < numPoints; p++) { 7627 PetscInt rStart = newPointOffsets[f][p]; 7628 PetscInt b = points[2 * p]; 7629 PetscInt c, r, k; 7630 PetscInt dof; 7631 7632 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7633 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7634 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7635 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7636 7637 for (r = 0; r < nRows; r++) { 7638 for (c = 0; c < newNumIndices; c++) { 7639 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7640 } 7641 } 7642 } else { 7643 /* copy this row as is */ 7644 for (r = 0; r < dof; r++) { 7645 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7646 } 7647 } 7648 oldOff += dof; 7649 } 7650 } 7651 } else { 7652 PetscInt oldOff = 0; 7653 7654 for (p = 0; p < numPoints; p++) { 7655 PetscInt rStart = newPointOffsets[0][p]; 7656 PetscInt b = points[2 * p]; 7657 PetscInt c, r, k; 7658 PetscInt dof; 7659 7660 PetscCall(PetscSectionGetDof(section, b, &dof)); 7661 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7662 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7663 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7664 7665 for (r = 0; r < nRows; r++) { 7666 for (c = 0; c < newNumIndices; c++) { 7667 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7668 } 7669 } 7670 } else { 7671 /* copy this row as is */ 7672 for (r = 0; r < dof; r++) { 7673 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7674 } 7675 } 7676 oldOff += dof; 7677 } 7678 } 7679 7680 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7681 } else { 7682 newValues = tmpValues; 7683 } 7684 } 7685 7686 /* clean up */ 7687 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7688 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7689 7690 if (numFields) { 7691 for (f = 0; f < numFields; f++) { 7692 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7693 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7694 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7695 } 7696 } else { 7697 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7698 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7699 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7700 } 7701 PetscCall(ISRestoreIndices(aIS, &anchors)); 7702 7703 /* output */ 7704 if (outPoints) { 7705 *outPoints = newPoints; 7706 } else { 7707 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7708 } 7709 if (outValues) *outValues = newValues; 7710 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7711 PetscFunctionReturn(PETSC_SUCCESS); 7712 } 7713 7714 /*@C 7715 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7716 7717 Not collective 7718 7719 Input Parameters: 7720 + dm - The `DM` 7721 . section - The `PetscSection` describing the points (a local section) 7722 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7723 . point - The point defining the closure 7724 - useClPerm - Use the closure point permutation if available 7725 7726 Output Parameters: 7727 + numIndices - The number of dof indices in the closure of point with the input sections 7728 . indices - The dof indices 7729 . outOffsets - Array to write the field offsets into, or `NULL` 7730 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7731 7732 Level: advanced 7733 7734 Notes: 7735 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7736 7737 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7738 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7739 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7740 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7741 indices (with the above semantics) are implied. 7742 7743 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7744 `PetscSection`, `DMGetGlobalSection()` 7745 @*/ 7746 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7747 { 7748 /* Closure ordering */ 7749 PetscSection clSection; 7750 IS clPoints; 7751 const PetscInt *clp; 7752 PetscInt *points; 7753 const PetscInt *clperm = NULL; 7754 /* Dof permutation and sign flips */ 7755 const PetscInt **perms[32] = {NULL}; 7756 const PetscScalar **flips[32] = {NULL}; 7757 PetscScalar *valCopy = NULL; 7758 /* Hanging node constraints */ 7759 PetscInt *pointsC = NULL; 7760 PetscScalar *valuesC = NULL; 7761 PetscInt NclC, NiC; 7762 7763 PetscInt *idx; 7764 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7765 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7766 7767 PetscFunctionBeginHot; 7768 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7769 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7770 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7771 if (numIndices) PetscAssertPointer(numIndices, 6); 7772 if (indices) PetscAssertPointer(indices, 7); 7773 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7774 if (values) PetscAssertPointer(values, 9); 7775 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7776 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7777 PetscCall(PetscArrayzero(offsets, 32)); 7778 /* 1) Get points in closure */ 7779 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7780 if (useClPerm) { 7781 PetscInt depth, clsize; 7782 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7783 for (clsize = 0, p = 0; p < Ncl; p++) { 7784 PetscInt dof; 7785 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7786 clsize += dof; 7787 } 7788 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7789 } 7790 /* 2) Get number of indices on these points and field offsets from section */ 7791 for (p = 0; p < Ncl * 2; p += 2) { 7792 PetscInt dof, fdof; 7793 7794 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7795 for (f = 0; f < Nf; ++f) { 7796 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7797 offsets[f + 1] += fdof; 7798 } 7799 Ni += dof; 7800 } 7801 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7802 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7803 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7804 for (f = 0; f < PetscMax(1, Nf); ++f) { 7805 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7806 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7807 /* may need to apply sign changes to the element matrix */ 7808 if (values && flips[f]) { 7809 PetscInt foffset = offsets[f]; 7810 7811 for (p = 0; p < Ncl; ++p) { 7812 PetscInt pnt = points[2 * p], fdof; 7813 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7814 7815 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7816 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7817 if (flip) { 7818 PetscInt i, j, k; 7819 7820 if (!valCopy) { 7821 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7822 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7823 *values = valCopy; 7824 } 7825 for (i = 0; i < fdof; ++i) { 7826 PetscScalar fval = flip[i]; 7827 7828 for (k = 0; k < Ni; ++k) { 7829 valCopy[Ni * (foffset + i) + k] *= fval; 7830 valCopy[Ni * k + (foffset + i)] *= fval; 7831 } 7832 } 7833 } 7834 foffset += fdof; 7835 } 7836 } 7837 } 7838 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7839 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7840 if (NclC) { 7841 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7842 for (f = 0; f < PetscMax(1, Nf); ++f) { 7843 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7844 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7845 } 7846 for (f = 0; f < PetscMax(1, Nf); ++f) { 7847 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7848 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7849 } 7850 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7851 Ncl = NclC; 7852 Ni = NiC; 7853 points = pointsC; 7854 if (values) *values = valuesC; 7855 } 7856 /* 5) Calculate indices */ 7857 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7858 if (Nf) { 7859 PetscInt idxOff; 7860 PetscBool useFieldOffsets; 7861 7862 if (outOffsets) { 7863 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7864 } 7865 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7866 if (useFieldOffsets) { 7867 for (p = 0; p < Ncl; ++p) { 7868 const PetscInt pnt = points[p * 2]; 7869 7870 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7871 } 7872 } else { 7873 for (p = 0; p < Ncl; ++p) { 7874 const PetscInt pnt = points[p * 2]; 7875 7876 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7877 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7878 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7879 * global section. */ 7880 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7881 } 7882 } 7883 } else { 7884 PetscInt off = 0, idxOff; 7885 7886 for (p = 0; p < Ncl; ++p) { 7887 const PetscInt pnt = points[p * 2]; 7888 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7889 7890 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7891 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7892 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7893 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7894 } 7895 } 7896 /* 6) Cleanup */ 7897 for (f = 0; f < PetscMax(1, Nf); ++f) { 7898 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7899 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7900 } 7901 if (NclC) { 7902 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7903 } else { 7904 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7905 } 7906 7907 if (numIndices) *numIndices = Ni; 7908 if (indices) *indices = idx; 7909 PetscFunctionReturn(PETSC_SUCCESS); 7910 } 7911 7912 /*@C 7913 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7914 7915 Not collective 7916 7917 Input Parameters: 7918 + dm - The `DM` 7919 . section - The `PetscSection` describing the points (a local section) 7920 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7921 . point - The point defining the closure 7922 - useClPerm - Use the closure point permutation if available 7923 7924 Output Parameters: 7925 + numIndices - The number of dof indices in the closure of point with the input sections 7926 . indices - The dof indices 7927 . outOffsets - Array to write the field offsets into, or `NULL` 7928 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7929 7930 Level: advanced 7931 7932 Notes: 7933 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7934 7935 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7936 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7937 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7938 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7939 indices (with the above semantics) are implied. 7940 7941 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7942 @*/ 7943 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7944 { 7945 PetscFunctionBegin; 7946 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7947 PetscAssertPointer(indices, 7); 7948 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7949 PetscFunctionReturn(PETSC_SUCCESS); 7950 } 7951 7952 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7953 { 7954 DM_Plex *mesh = (DM_Plex *)dm->data; 7955 PetscInt *indices; 7956 PetscInt numIndices; 7957 const PetscScalar *valuesOrig = values; 7958 PetscErrorCode ierr; 7959 7960 PetscFunctionBegin; 7961 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7962 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7963 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7964 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7965 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7966 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 7967 7968 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7969 7970 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7971 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7972 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7973 if (ierr) { 7974 PetscMPIInt rank; 7975 7976 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7977 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7978 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7979 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7980 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7981 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7982 } 7983 if (mesh->printFEM > 1) { 7984 PetscInt i; 7985 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7986 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7987 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7988 } 7989 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 PetscFunctionReturn(PETSC_SUCCESS); 7993 } 7994 7995 /*@C 7996 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7997 7998 Not collective 7999 8000 Input Parameters: 8001 + dm - The `DM` 8002 . section - The section describing the layout in `v`, or `NULL` to use the default section 8003 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8004 . A - The matrix 8005 . point - The point in the `DM` 8006 . values - The array of values 8007 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8008 8009 Level: intermediate 8010 8011 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8012 @*/ 8013 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8014 { 8015 PetscFunctionBegin; 8016 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8017 PetscFunctionReturn(PETSC_SUCCESS); 8018 } 8019 8020 /*@C 8021 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8022 8023 Not collective 8024 8025 Input Parameters: 8026 + dmRow - The `DM` for the row fields 8027 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8028 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8029 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8030 . dmCol - The `DM` for the column fields 8031 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8032 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8033 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8034 . A - The matrix 8035 . point - The point in the `DM` 8036 . values - The array of values 8037 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8038 8039 Level: intermediate 8040 8041 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8042 @*/ 8043 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) 8044 { 8045 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8046 PetscInt *indicesRow, *indicesCol; 8047 PetscInt numIndicesRow, numIndicesCol; 8048 const PetscScalar *valuesOrig = values; 8049 PetscErrorCode ierr; 8050 8051 PetscFunctionBegin; 8052 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8053 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8054 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8055 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8056 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8057 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8058 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8059 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8060 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8061 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8062 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8063 8064 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8065 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8066 8067 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8068 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8069 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8070 if (ierr) { 8071 PetscMPIInt rank; 8072 8073 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8074 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8075 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8076 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8077 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8078 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8079 } 8080 8081 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8082 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8083 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8084 PetscFunctionReturn(PETSC_SUCCESS); 8085 } 8086 8087 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8088 { 8089 DM_Plex *mesh = (DM_Plex *)dmf->data; 8090 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8091 PetscInt *cpoints = NULL; 8092 PetscInt *findices, *cindices; 8093 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8094 PetscInt foffsets[32], coffsets[32]; 8095 DMPolytopeType ct; 8096 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8097 PetscErrorCode ierr; 8098 8099 PetscFunctionBegin; 8100 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8101 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8102 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8103 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8104 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8105 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8106 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8107 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8108 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8109 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8110 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8111 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8112 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8113 PetscCall(PetscArrayzero(foffsets, 32)); 8114 PetscCall(PetscArrayzero(coffsets, 32)); 8115 /* Column indices */ 8116 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8117 maxFPoints = numCPoints; 8118 /* Compress out points not in the section */ 8119 /* TODO: Squeeze out points with 0 dof as well */ 8120 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8121 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8122 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8123 cpoints[q * 2] = cpoints[p]; 8124 cpoints[q * 2 + 1] = cpoints[p + 1]; 8125 ++q; 8126 } 8127 } 8128 numCPoints = q; 8129 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8130 PetscInt fdof; 8131 8132 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8133 if (!dof) continue; 8134 for (f = 0; f < numFields; ++f) { 8135 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8136 coffsets[f + 1] += fdof; 8137 } 8138 numCIndices += dof; 8139 } 8140 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8141 /* Row indices */ 8142 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8143 { 8144 DMPlexTransform tr; 8145 DMPolytopeType *rct; 8146 PetscInt *rsize, *rcone, *rornt, Nt; 8147 8148 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8149 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8150 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8151 numSubcells = rsize[Nt - 1]; 8152 PetscCall(DMPlexTransformDestroy(&tr)); 8153 } 8154 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8155 for (r = 0, q = 0; r < numSubcells; ++r) { 8156 /* TODO Map from coarse to fine cells */ 8157 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8158 /* Compress out points not in the section */ 8159 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8160 for (p = 0; p < numFPoints * 2; p += 2) { 8161 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8162 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8163 if (!dof) continue; 8164 for (s = 0; s < q; ++s) 8165 if (fpoints[p] == ftotpoints[s * 2]) break; 8166 if (s < q) continue; 8167 ftotpoints[q * 2] = fpoints[p]; 8168 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8169 ++q; 8170 } 8171 } 8172 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8173 } 8174 numFPoints = q; 8175 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8176 PetscInt fdof; 8177 8178 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8179 if (!dof) continue; 8180 for (f = 0; f < numFields; ++f) { 8181 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8182 foffsets[f + 1] += fdof; 8183 } 8184 numFIndices += dof; 8185 } 8186 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8187 8188 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8189 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8190 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8191 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8192 if (numFields) { 8193 const PetscInt **permsF[32] = {NULL}; 8194 const PetscInt **permsC[32] = {NULL}; 8195 8196 for (f = 0; f < numFields; f++) { 8197 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8198 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8199 } 8200 for (p = 0; p < numFPoints; p++) { 8201 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8202 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8203 } 8204 for (p = 0; p < numCPoints; p++) { 8205 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8206 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8207 } 8208 for (f = 0; f < numFields; f++) { 8209 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8210 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8211 } 8212 } else { 8213 const PetscInt **permsF = NULL; 8214 const PetscInt **permsC = NULL; 8215 8216 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8217 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8218 for (p = 0, off = 0; p < numFPoints; p++) { 8219 const PetscInt *perm = permsF ? permsF[p] : NULL; 8220 8221 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8222 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8223 } 8224 for (p = 0, off = 0; p < numCPoints; p++) { 8225 const PetscInt *perm = permsC ? permsC[p] : NULL; 8226 8227 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8228 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8229 } 8230 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8231 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8232 } 8233 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8234 /* TODO: flips */ 8235 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8236 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8237 if (ierr) { 8238 PetscMPIInt rank; 8239 8240 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8241 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8242 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8243 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8244 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8245 } 8246 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8247 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8248 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8249 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8250 PetscFunctionReturn(PETSC_SUCCESS); 8251 } 8252 8253 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8254 { 8255 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8256 PetscInt *cpoints = NULL; 8257 PetscInt foffsets[32], coffsets[32]; 8258 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8259 DMPolytopeType ct; 8260 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8261 8262 PetscFunctionBegin; 8263 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8264 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8265 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8266 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8267 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8268 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8269 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8270 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8271 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8272 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8273 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8274 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8275 PetscCall(PetscArrayzero(foffsets, 32)); 8276 PetscCall(PetscArrayzero(coffsets, 32)); 8277 /* Column indices */ 8278 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8279 maxFPoints = numCPoints; 8280 /* Compress out points not in the section */ 8281 /* TODO: Squeeze out points with 0 dof as well */ 8282 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8283 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8284 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8285 cpoints[q * 2] = cpoints[p]; 8286 cpoints[q * 2 + 1] = cpoints[p + 1]; 8287 ++q; 8288 } 8289 } 8290 numCPoints = q; 8291 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8292 PetscInt fdof; 8293 8294 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8295 if (!dof) continue; 8296 for (f = 0; f < numFields; ++f) { 8297 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8298 coffsets[f + 1] += fdof; 8299 } 8300 numCIndices += dof; 8301 } 8302 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8303 /* Row indices */ 8304 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8305 { 8306 DMPlexTransform tr; 8307 DMPolytopeType *rct; 8308 PetscInt *rsize, *rcone, *rornt, Nt; 8309 8310 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8311 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8312 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8313 numSubcells = rsize[Nt - 1]; 8314 PetscCall(DMPlexTransformDestroy(&tr)); 8315 } 8316 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8317 for (r = 0, q = 0; r < numSubcells; ++r) { 8318 /* TODO Map from coarse to fine cells */ 8319 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8320 /* Compress out points not in the section */ 8321 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8322 for (p = 0; p < numFPoints * 2; p += 2) { 8323 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8324 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8325 if (!dof) continue; 8326 for (s = 0; s < q; ++s) 8327 if (fpoints[p] == ftotpoints[s * 2]) break; 8328 if (s < q) continue; 8329 ftotpoints[q * 2] = fpoints[p]; 8330 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8331 ++q; 8332 } 8333 } 8334 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8335 } 8336 numFPoints = q; 8337 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8338 PetscInt fdof; 8339 8340 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8341 if (!dof) continue; 8342 for (f = 0; f < numFields; ++f) { 8343 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8344 foffsets[f + 1] += fdof; 8345 } 8346 numFIndices += dof; 8347 } 8348 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8349 8350 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8351 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8352 if (numFields) { 8353 const PetscInt **permsF[32] = {NULL}; 8354 const PetscInt **permsC[32] = {NULL}; 8355 8356 for (f = 0; f < numFields; f++) { 8357 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8358 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8359 } 8360 for (p = 0; p < numFPoints; p++) { 8361 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8362 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8363 } 8364 for (p = 0; p < numCPoints; p++) { 8365 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8366 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8367 } 8368 for (f = 0; f < numFields; f++) { 8369 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8370 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8371 } 8372 } else { 8373 const PetscInt **permsF = NULL; 8374 const PetscInt **permsC = NULL; 8375 8376 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8377 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8378 for (p = 0, off = 0; p < numFPoints; p++) { 8379 const PetscInt *perm = permsF ? permsF[p] : NULL; 8380 8381 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8382 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8383 } 8384 for (p = 0, off = 0; p < numCPoints; p++) { 8385 const PetscInt *perm = permsC ? permsC[p] : NULL; 8386 8387 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8388 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8389 } 8390 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8391 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8392 } 8393 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8394 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8395 PetscFunctionReturn(PETSC_SUCCESS); 8396 } 8397 8398 /*@C 8399 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8400 8401 Input Parameter: 8402 . dm - The `DMPLEX` object 8403 8404 Output Parameter: 8405 . cellHeight - The height of a cell 8406 8407 Level: developer 8408 8409 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8410 @*/ 8411 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8412 { 8413 DM_Plex *mesh = (DM_Plex *)dm->data; 8414 8415 PetscFunctionBegin; 8416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8417 PetscAssertPointer(cellHeight, 2); 8418 *cellHeight = mesh->vtkCellHeight; 8419 PetscFunctionReturn(PETSC_SUCCESS); 8420 } 8421 8422 /*@C 8423 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8424 8425 Input Parameters: 8426 + dm - The `DMPLEX` object 8427 - cellHeight - The height of a cell 8428 8429 Level: developer 8430 8431 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8432 @*/ 8433 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8434 { 8435 DM_Plex *mesh = (DM_Plex *)dm->data; 8436 8437 PetscFunctionBegin; 8438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8439 mesh->vtkCellHeight = cellHeight; 8440 PetscFunctionReturn(PETSC_SUCCESS); 8441 } 8442 8443 /*@ 8444 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8445 8446 Input Parameters: 8447 + dm - The `DMPLEX` object 8448 - ct - The `DMPolytopeType` of the cell 8449 8450 Output Parameters: 8451 + start - The first cell of this type, or `NULL` 8452 - end - The upper bound on this celltype, or `NULL` 8453 8454 Level: advanced 8455 8456 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8457 @*/ 8458 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8459 { 8460 DM_Plex *mesh = (DM_Plex *)dm->data; 8461 DMLabel label; 8462 PetscInt pStart, pEnd; 8463 8464 PetscFunctionBegin; 8465 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8466 if (start) { 8467 PetscAssertPointer(start, 3); 8468 *start = 0; 8469 } 8470 if (end) { 8471 PetscAssertPointer(end, 4); 8472 *end = 0; 8473 } 8474 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8475 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8476 if (mesh->tr) { 8477 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8478 } else { 8479 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8480 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8481 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8482 } 8483 PetscFunctionReturn(PETSC_SUCCESS); 8484 } 8485 8486 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8487 { 8488 PetscSection section, globalSection; 8489 PetscInt *numbers, p; 8490 8491 PetscFunctionBegin; 8492 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8493 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8494 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8495 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8496 PetscCall(PetscSectionSetUp(section)); 8497 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8498 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8499 for (p = pStart; p < pEnd; ++p) { 8500 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8501 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8502 else numbers[p - pStart] += shift; 8503 } 8504 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8505 if (globalSize) { 8506 PetscLayout layout; 8507 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8508 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8509 PetscCall(PetscLayoutDestroy(&layout)); 8510 } 8511 PetscCall(PetscSectionDestroy(§ion)); 8512 PetscCall(PetscSectionDestroy(&globalSection)); 8513 PetscFunctionReturn(PETSC_SUCCESS); 8514 } 8515 8516 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8517 { 8518 PetscInt cellHeight, cStart, cEnd; 8519 8520 PetscFunctionBegin; 8521 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8522 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8523 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8524 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8525 PetscFunctionReturn(PETSC_SUCCESS); 8526 } 8527 8528 /*@ 8529 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8530 8531 Input Parameter: 8532 . dm - The `DMPLEX` object 8533 8534 Output Parameter: 8535 . globalCellNumbers - Global cell numbers for all cells on this process 8536 8537 Level: developer 8538 8539 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8540 @*/ 8541 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8542 { 8543 DM_Plex *mesh = (DM_Plex *)dm->data; 8544 8545 PetscFunctionBegin; 8546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8547 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8548 *globalCellNumbers = mesh->globalCellNumbers; 8549 PetscFunctionReturn(PETSC_SUCCESS); 8550 } 8551 8552 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8553 { 8554 PetscInt vStart, vEnd; 8555 8556 PetscFunctionBegin; 8557 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8558 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8559 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8560 PetscFunctionReturn(PETSC_SUCCESS); 8561 } 8562 8563 /*@ 8564 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8565 8566 Input Parameter: 8567 . dm - The `DMPLEX` object 8568 8569 Output Parameter: 8570 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8571 8572 Level: developer 8573 8574 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8575 @*/ 8576 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8577 { 8578 DM_Plex *mesh = (DM_Plex *)dm->data; 8579 8580 PetscFunctionBegin; 8581 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8582 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8583 *globalVertexNumbers = mesh->globalVertexNumbers; 8584 PetscFunctionReturn(PETSC_SUCCESS); 8585 } 8586 8587 /*@ 8588 DMPlexCreatePointNumbering - Create a global numbering for all points. 8589 8590 Collective 8591 8592 Input Parameter: 8593 . dm - The `DMPLEX` object 8594 8595 Output Parameter: 8596 . globalPointNumbers - Global numbers for all points on this process 8597 8598 Level: developer 8599 8600 Notes: 8601 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8602 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8603 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8604 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8605 8606 The partitioned mesh is 8607 ``` 8608 (2)--0--(3)--1--(4) (1)--0--(2) 8609 ``` 8610 and its global numbering is 8611 ``` 8612 (3)--0--(4)--1--(5)--2--(6) 8613 ``` 8614 Then the global numbering is provided as 8615 ``` 8616 [0] Number of indices in set 5 8617 [0] 0 0 8618 [0] 1 1 8619 [0] 2 3 8620 [0] 3 4 8621 [0] 4 -6 8622 [1] Number of indices in set 3 8623 [1] 0 2 8624 [1] 1 5 8625 [1] 2 6 8626 ``` 8627 8628 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8629 @*/ 8630 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8631 { 8632 IS nums[4]; 8633 PetscInt depths[4], gdepths[4], starts[4]; 8634 PetscInt depth, d, shift = 0; 8635 PetscBool empty = PETSC_FALSE; 8636 8637 PetscFunctionBegin; 8638 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8639 PetscCall(DMPlexGetDepth(dm, &depth)); 8640 // For unstratified meshes use dim instead of depth 8641 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8642 // If any stratum is empty, we must mark all empty 8643 for (d = 0; d <= depth; ++d) { 8644 PetscInt end; 8645 8646 depths[d] = depth - d; 8647 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8648 if (!(starts[d] - end)) empty = PETSC_TRUE; 8649 } 8650 if (empty) 8651 for (d = 0; d <= depth; ++d) { 8652 depths[d] = -1; 8653 starts[d] = -1; 8654 } 8655 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8656 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8657 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]); 8658 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8659 for (d = 0; d <= depth; ++d) { 8660 PetscInt pStart, pEnd, gsize; 8661 8662 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8663 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8664 shift += gsize; 8665 } 8666 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8667 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8668 PetscFunctionReturn(PETSC_SUCCESS); 8669 } 8670 8671 /*@ 8672 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8673 8674 Input Parameter: 8675 . dm - The `DMPLEX` object 8676 8677 Output Parameter: 8678 . ranks - The rank field 8679 8680 Options Database Key: 8681 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8682 8683 Level: intermediate 8684 8685 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8686 @*/ 8687 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8688 { 8689 DM rdm; 8690 PetscFE fe; 8691 PetscScalar *r; 8692 PetscMPIInt rank; 8693 DMPolytopeType ct; 8694 PetscInt dim, cStart, cEnd, c; 8695 PetscBool simplex; 8696 8697 PetscFunctionBeginUser; 8698 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8699 PetscAssertPointer(ranks, 2); 8700 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8701 PetscCall(DMClone(dm, &rdm)); 8702 PetscCall(DMGetDimension(rdm, &dim)); 8703 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8704 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8705 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8706 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8707 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8708 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8709 PetscCall(PetscFEDestroy(&fe)); 8710 PetscCall(DMCreateDS(rdm)); 8711 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8712 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8713 PetscCall(VecGetArray(*ranks, &r)); 8714 for (c = cStart; c < cEnd; ++c) { 8715 PetscScalar *lr; 8716 8717 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8718 if (lr) *lr = rank; 8719 } 8720 PetscCall(VecRestoreArray(*ranks, &r)); 8721 PetscCall(DMDestroy(&rdm)); 8722 PetscFunctionReturn(PETSC_SUCCESS); 8723 } 8724 8725 /*@ 8726 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8727 8728 Input Parameters: 8729 + dm - The `DMPLEX` 8730 - label - The `DMLabel` 8731 8732 Output Parameter: 8733 . val - The label value field 8734 8735 Options Database Key: 8736 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8737 8738 Level: intermediate 8739 8740 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8741 @*/ 8742 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8743 { 8744 DM rdm; 8745 PetscFE fe; 8746 PetscScalar *v; 8747 PetscInt dim, cStart, cEnd, c; 8748 8749 PetscFunctionBeginUser; 8750 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8751 PetscAssertPointer(label, 2); 8752 PetscAssertPointer(val, 3); 8753 PetscCall(DMClone(dm, &rdm)); 8754 PetscCall(DMGetDimension(rdm, &dim)); 8755 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8756 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8757 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8758 PetscCall(PetscFEDestroy(&fe)); 8759 PetscCall(DMCreateDS(rdm)); 8760 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8761 PetscCall(DMCreateGlobalVector(rdm, val)); 8762 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8763 PetscCall(VecGetArray(*val, &v)); 8764 for (c = cStart; c < cEnd; ++c) { 8765 PetscScalar *lv; 8766 PetscInt cval; 8767 8768 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8769 PetscCall(DMLabelGetValue(label, c, &cval)); 8770 *lv = cval; 8771 } 8772 PetscCall(VecRestoreArray(*val, &v)); 8773 PetscCall(DMDestroy(&rdm)); 8774 PetscFunctionReturn(PETSC_SUCCESS); 8775 } 8776 8777 /*@ 8778 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8779 8780 Input Parameter: 8781 . dm - The `DMPLEX` object 8782 8783 Level: developer 8784 8785 Notes: 8786 This is a useful diagnostic when creating meshes programmatically. 8787 8788 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8789 8790 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8791 @*/ 8792 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8793 { 8794 PetscSection coneSection, supportSection; 8795 const PetscInt *cone, *support; 8796 PetscInt coneSize, c, supportSize, s; 8797 PetscInt pStart, pEnd, p, pp, csize, ssize; 8798 PetscBool storagecheck = PETSC_TRUE; 8799 8800 PetscFunctionBegin; 8801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8802 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8803 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8804 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8805 /* Check that point p is found in the support of its cone points, and vice versa */ 8806 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8807 for (p = pStart; p < pEnd; ++p) { 8808 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8809 PetscCall(DMPlexGetCone(dm, p, &cone)); 8810 for (c = 0; c < coneSize; ++c) { 8811 PetscBool dup = PETSC_FALSE; 8812 PetscInt d; 8813 for (d = c - 1; d >= 0; --d) { 8814 if (cone[c] == cone[d]) { 8815 dup = PETSC_TRUE; 8816 break; 8817 } 8818 } 8819 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8820 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8821 for (s = 0; s < supportSize; ++s) { 8822 if (support[s] == p) break; 8823 } 8824 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8825 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8826 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8827 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8828 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8829 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8830 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8831 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]); 8832 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8833 } 8834 } 8835 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8836 if (p != pp) { 8837 storagecheck = PETSC_FALSE; 8838 continue; 8839 } 8840 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8841 PetscCall(DMPlexGetSupport(dm, p, &support)); 8842 for (s = 0; s < supportSize; ++s) { 8843 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8844 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8845 for (c = 0; c < coneSize; ++c) { 8846 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8847 if (cone[c] != pp) { 8848 c = 0; 8849 break; 8850 } 8851 if (cone[c] == p) break; 8852 } 8853 if (c >= coneSize) { 8854 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8855 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8856 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8857 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8858 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8859 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8860 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8861 } 8862 } 8863 } 8864 if (storagecheck) { 8865 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8866 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8867 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8868 } 8869 PetscFunctionReturn(PETSC_SUCCESS); 8870 } 8871 8872 /* 8873 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. 8874 */ 8875 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8876 { 8877 DMPolytopeType cct; 8878 PetscInt ptpoints[4]; 8879 const PetscInt *cone, *ccone, *ptcone; 8880 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8881 8882 PetscFunctionBegin; 8883 *unsplit = 0; 8884 switch (ct) { 8885 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8886 ptpoints[npt++] = c; 8887 break; 8888 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8889 PetscCall(DMPlexGetCone(dm, c, &cone)); 8890 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8891 for (cp = 0; cp < coneSize; ++cp) { 8892 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8893 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8894 } 8895 break; 8896 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8897 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8898 PetscCall(DMPlexGetCone(dm, c, &cone)); 8899 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8900 for (cp = 0; cp < coneSize; ++cp) { 8901 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8902 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8903 for (ccp = 0; ccp < cconeSize; ++ccp) { 8904 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8905 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8906 PetscInt p; 8907 for (p = 0; p < npt; ++p) 8908 if (ptpoints[p] == ccone[ccp]) break; 8909 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8910 } 8911 } 8912 } 8913 break; 8914 default: 8915 break; 8916 } 8917 for (pt = 0; pt < npt; ++pt) { 8918 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8919 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8920 } 8921 PetscFunctionReturn(PETSC_SUCCESS); 8922 } 8923 8924 /*@ 8925 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8926 8927 Input Parameters: 8928 + dm - The `DMPLEX` object 8929 - cellHeight - Normally 0 8930 8931 Level: developer 8932 8933 Notes: 8934 This is a useful diagnostic when creating meshes programmatically. 8935 Currently applicable only to homogeneous simplex or tensor meshes. 8936 8937 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8938 8939 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8940 @*/ 8941 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8942 { 8943 DMPlexInterpolatedFlag interp; 8944 DMPolytopeType ct; 8945 PetscInt vStart, vEnd, cStart, cEnd, c; 8946 8947 PetscFunctionBegin; 8948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8949 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8950 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8951 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8952 for (c = cStart; c < cEnd; ++c) { 8953 PetscInt *closure = NULL; 8954 PetscInt coneSize, closureSize, cl, Nv = 0; 8955 8956 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8957 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8958 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8959 if (interp == DMPLEX_INTERPOLATED_FULL) { 8960 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8961 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)); 8962 } 8963 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8964 for (cl = 0; cl < closureSize * 2; cl += 2) { 8965 const PetscInt p = closure[cl]; 8966 if ((p >= vStart) && (p < vEnd)) ++Nv; 8967 } 8968 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8969 /* Special Case: Tensor faces with identified vertices */ 8970 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8971 PetscInt unsplit; 8972 8973 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8974 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8975 } 8976 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)); 8977 } 8978 PetscFunctionReturn(PETSC_SUCCESS); 8979 } 8980 8981 /*@ 8982 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8983 8984 Collective 8985 8986 Input Parameters: 8987 + dm - The `DMPLEX` object 8988 - cellHeight - Normally 0 8989 8990 Level: developer 8991 8992 Notes: 8993 This is a useful diagnostic when creating meshes programmatically. 8994 This routine is only relevant for meshes that are fully interpolated across all ranks. 8995 It will error out if a partially interpolated mesh is given on some rank. 8996 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8997 8998 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8999 9000 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9001 @*/ 9002 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9003 { 9004 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9005 DMPlexInterpolatedFlag interpEnum; 9006 9007 PetscFunctionBegin; 9008 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9009 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9010 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9011 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9012 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9013 PetscFunctionReturn(PETSC_SUCCESS); 9014 } 9015 9016 PetscCall(DMGetDimension(dm, &dim)); 9017 PetscCall(DMPlexGetDepth(dm, &depth)); 9018 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9019 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9020 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9021 for (c = cStart; c < cEnd; ++c) { 9022 const PetscInt *cone, *ornt, *faceSizes, *faces; 9023 const DMPolytopeType *faceTypes; 9024 DMPolytopeType ct; 9025 PetscInt numFaces, coneSize, f; 9026 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9027 9028 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9029 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9030 if (unsplit) continue; 9031 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9032 PetscCall(DMPlexGetCone(dm, c, &cone)); 9033 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9034 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9035 for (cl = 0; cl < closureSize * 2; cl += 2) { 9036 const PetscInt p = closure[cl]; 9037 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9038 } 9039 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9040 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); 9041 for (f = 0; f < numFaces; ++f) { 9042 DMPolytopeType fct; 9043 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9044 9045 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9046 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9047 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9048 const PetscInt p = fclosure[cl]; 9049 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9050 } 9051 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]); 9052 for (v = 0; v < fnumCorners; ++v) { 9053 if (fclosure[v] != faces[fOff + v]) { 9054 PetscInt v1; 9055 9056 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9057 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9058 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9059 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9060 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9061 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]); 9062 } 9063 } 9064 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9065 fOff += faceSizes[f]; 9066 } 9067 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9068 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9069 } 9070 } 9071 PetscFunctionReturn(PETSC_SUCCESS); 9072 } 9073 9074 /*@ 9075 DMPlexCheckGeometry - Check the geometry of mesh cells 9076 9077 Input Parameter: 9078 . dm - The `DMPLEX` object 9079 9080 Level: developer 9081 9082 Notes: 9083 This is a useful diagnostic when creating meshes programmatically. 9084 9085 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9086 9087 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9088 @*/ 9089 PetscErrorCode DMPlexCheckGeometry(DM dm) 9090 { 9091 Vec coordinates; 9092 PetscReal detJ, J[9], refVol = 1.0; 9093 PetscReal vol; 9094 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9095 9096 PetscFunctionBegin; 9097 PetscCall(DMGetDimension(dm, &dim)); 9098 PetscCall(DMGetCoordinateDim(dm, &dE)); 9099 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9100 PetscCall(DMPlexGetDepth(dm, &depth)); 9101 for (d = 0; d < dim; ++d) refVol *= 2.0; 9102 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9103 /* Make sure local coordinates are created, because that step is collective */ 9104 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9105 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9106 for (c = cStart; c < cEnd; ++c) { 9107 DMPolytopeType ct; 9108 PetscInt unsplit; 9109 PetscBool ignoreZeroVol = PETSC_FALSE; 9110 9111 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9112 switch (ct) { 9113 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9114 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9115 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9116 ignoreZeroVol = PETSC_TRUE; 9117 break; 9118 default: 9119 break; 9120 } 9121 switch (ct) { 9122 case DM_POLYTOPE_TRI_PRISM: 9123 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9124 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9125 case DM_POLYTOPE_PYRAMID: 9126 continue; 9127 default: 9128 break; 9129 } 9130 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9131 if (unsplit) continue; 9132 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9133 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); 9134 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9135 /* This should work with periodicity since DG coordinates should be used */ 9136 if (depth > 1) { 9137 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9138 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); 9139 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9140 } 9141 } 9142 PetscFunctionReturn(PETSC_SUCCESS); 9143 } 9144 9145 /*@ 9146 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9147 9148 Collective 9149 9150 Input Parameters: 9151 + dm - The `DMPLEX` object 9152 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9153 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9154 9155 Level: developer 9156 9157 Notes: 9158 This is mainly intended for debugging/testing purposes. 9159 9160 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9161 9162 Extra roots can come from periodic cuts, where additional points appear on the boundary 9163 9164 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9165 @*/ 9166 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9167 { 9168 PetscInt l, nleaves, nroots, overlap; 9169 const PetscInt *locals; 9170 const PetscSFNode *remotes; 9171 PetscBool distributed; 9172 MPI_Comm comm; 9173 PetscMPIInt rank; 9174 9175 PetscFunctionBegin; 9176 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9177 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9178 else pointSF = dm->sf; 9179 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9180 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9181 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9182 { 9183 PetscMPIInt mpiFlag; 9184 9185 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9186 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9187 } 9188 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9189 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9190 if (!distributed) { 9191 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); 9192 PetscFunctionReturn(PETSC_SUCCESS); 9193 } 9194 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); 9195 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9196 9197 /* Check SF graph is compatible with DMPlex chart */ 9198 { 9199 PetscInt pStart, pEnd, maxLeaf; 9200 9201 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9202 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9203 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9204 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9205 } 9206 9207 /* Check Point SF has no local points referenced */ 9208 for (l = 0; l < nleaves; l++) { 9209 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); 9210 } 9211 9212 /* Check there are no cells in interface */ 9213 if (!overlap) { 9214 PetscInt cellHeight, cStart, cEnd; 9215 9216 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9217 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9218 for (l = 0; l < nleaves; ++l) { 9219 const PetscInt point = locals ? locals[l] : l; 9220 9221 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9222 } 9223 } 9224 9225 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9226 { 9227 const PetscInt *rootdegree; 9228 9229 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9230 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9231 for (l = 0; l < nleaves; ++l) { 9232 const PetscInt point = locals ? locals[l] : l; 9233 const PetscInt *cone; 9234 PetscInt coneSize, c, idx; 9235 9236 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9237 PetscCall(DMPlexGetCone(dm, point, &cone)); 9238 for (c = 0; c < coneSize; ++c) { 9239 if (!rootdegree[cone[c]]) { 9240 if (locals) { 9241 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9242 } else { 9243 idx = (cone[c] < nleaves) ? cone[c] : -1; 9244 } 9245 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9246 } 9247 } 9248 } 9249 } 9250 PetscFunctionReturn(PETSC_SUCCESS); 9251 } 9252 9253 /*@ 9254 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9255 9256 Input Parameter: 9257 . dm - The `DMPLEX` object 9258 9259 Level: developer 9260 9261 Notes: 9262 This is a useful diagnostic when creating meshes programmatically. 9263 9264 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9265 9266 Currently does not include `DMPlexCheckCellShape()`. 9267 9268 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9269 @*/ 9270 PetscErrorCode DMPlexCheck(DM dm) 9271 { 9272 PetscInt cellHeight; 9273 9274 PetscFunctionBegin; 9275 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9276 PetscCall(DMPlexCheckSymmetry(dm)); 9277 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9278 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9279 PetscCall(DMPlexCheckGeometry(dm)); 9280 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9281 PetscCall(DMPlexCheckInterfaceCones(dm)); 9282 PetscFunctionReturn(PETSC_SUCCESS); 9283 } 9284 9285 typedef struct cell_stats { 9286 PetscReal min, max, sum, squaresum; 9287 PetscInt count; 9288 } cell_stats_t; 9289 9290 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9291 { 9292 PetscInt i, N = *len; 9293 9294 for (i = 0; i < N; i++) { 9295 cell_stats_t *A = (cell_stats_t *)a; 9296 cell_stats_t *B = (cell_stats_t *)b; 9297 9298 B->min = PetscMin(A->min, B->min); 9299 B->max = PetscMax(A->max, B->max); 9300 B->sum += A->sum; 9301 B->squaresum += A->squaresum; 9302 B->count += A->count; 9303 } 9304 } 9305 9306 /*@ 9307 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9308 9309 Collective 9310 9311 Input Parameters: 9312 + dm - The `DMPLEX` object 9313 . output - If true, statistics will be displayed on `stdout` 9314 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9315 9316 Level: developer 9317 9318 Notes: 9319 This is mainly intended for debugging/testing purposes. 9320 9321 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9322 9323 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9324 @*/ 9325 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9326 { 9327 DM dmCoarse; 9328 cell_stats_t stats, globalStats; 9329 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9330 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9331 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9332 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9333 PetscMPIInt rank, size; 9334 9335 PetscFunctionBegin; 9336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9337 stats.min = PETSC_MAX_REAL; 9338 stats.max = PETSC_MIN_REAL; 9339 stats.sum = stats.squaresum = 0.; 9340 stats.count = 0; 9341 9342 PetscCallMPI(MPI_Comm_size(comm, &size)); 9343 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9344 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9345 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9346 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9347 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9348 for (c = cStart; c < cEnd; c++) { 9349 PetscInt i; 9350 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9351 9352 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9353 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9354 for (i = 0; i < PetscSqr(cdim); ++i) { 9355 frobJ += J[i] * J[i]; 9356 frobInvJ += invJ[i] * invJ[i]; 9357 } 9358 cond2 = frobJ * frobInvJ; 9359 cond = PetscSqrtReal(cond2); 9360 9361 stats.min = PetscMin(stats.min, cond); 9362 stats.max = PetscMax(stats.max, cond); 9363 stats.sum += cond; 9364 stats.squaresum += cond2; 9365 stats.count++; 9366 if (output && cond > limit) { 9367 PetscSection coordSection; 9368 Vec coordsLocal; 9369 PetscScalar *coords = NULL; 9370 PetscInt Nv, d, clSize, cl, *closure = NULL; 9371 9372 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9373 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9374 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9375 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9376 for (i = 0; i < Nv / cdim; ++i) { 9377 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9378 for (d = 0; d < cdim; ++d) { 9379 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9380 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9381 } 9382 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9383 } 9384 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9385 for (cl = 0; cl < clSize * 2; cl += 2) { 9386 const PetscInt edge = closure[cl]; 9387 9388 if ((edge >= eStart) && (edge < eEnd)) { 9389 PetscReal len; 9390 9391 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9392 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9393 } 9394 } 9395 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9396 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9397 } 9398 } 9399 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9400 9401 if (size > 1) { 9402 PetscMPIInt blockLengths[2] = {4, 1}; 9403 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9404 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9405 MPI_Op statReduce; 9406 9407 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9408 PetscCallMPI(MPI_Type_commit(&statType)); 9409 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9410 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9411 PetscCallMPI(MPI_Op_free(&statReduce)); 9412 PetscCallMPI(MPI_Type_free(&statType)); 9413 } else { 9414 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9415 } 9416 if (rank == 0) { 9417 count = globalStats.count; 9418 min = globalStats.min; 9419 max = globalStats.max; 9420 mean = globalStats.sum / globalStats.count; 9421 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9422 } 9423 9424 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)); 9425 PetscCall(PetscFree2(J, invJ)); 9426 9427 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9428 if (dmCoarse) { 9429 PetscBool isplex; 9430 9431 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9432 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9433 } 9434 PetscFunctionReturn(PETSC_SUCCESS); 9435 } 9436 9437 /*@ 9438 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9439 orthogonal quality below given tolerance. 9440 9441 Collective 9442 9443 Input Parameters: 9444 + dm - The `DMPLEX` object 9445 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9446 - atol - [0, 1] Absolute tolerance for tagging cells. 9447 9448 Output Parameters: 9449 + OrthQual - `Vec` containing orthogonal quality per cell 9450 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9451 9452 Options Database Keys: 9453 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9454 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9455 9456 Level: intermediate 9457 9458 Notes: 9459 Orthogonal quality is given by the following formula\: 9460 9461 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9462 9463 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 9464 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9465 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9466 calculating the cosine of the angle between these vectors. 9467 9468 Orthogonal quality ranges from 1 (best) to 0 (worst). 9469 9470 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9471 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9472 9473 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9474 9475 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9476 @*/ 9477 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9478 { 9479 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9480 PetscInt *idx; 9481 PetscScalar *oqVals; 9482 const PetscScalar *cellGeomArr, *faceGeomArr; 9483 PetscReal *ci, *fi, *Ai; 9484 MPI_Comm comm; 9485 Vec cellgeom, facegeom; 9486 DM dmFace, dmCell; 9487 IS glob; 9488 ISLocalToGlobalMapping ltog; 9489 PetscViewer vwr; 9490 9491 PetscFunctionBegin; 9492 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9493 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9494 PetscAssertPointer(OrthQual, 4); 9495 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9496 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9497 PetscCall(DMGetDimension(dm, &nc)); 9498 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9499 { 9500 DMPlexInterpolatedFlag interpFlag; 9501 9502 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9503 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9504 PetscMPIInt rank; 9505 9506 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9507 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9508 } 9509 } 9510 if (OrthQualLabel) { 9511 PetscAssertPointer(OrthQualLabel, 5); 9512 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9513 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9514 } else { 9515 *OrthQualLabel = NULL; 9516 } 9517 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9518 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9519 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9520 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9521 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9522 PetscCall(VecCreate(comm, OrthQual)); 9523 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9524 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9525 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9526 PetscCall(VecSetUp(*OrthQual)); 9527 PetscCall(ISDestroy(&glob)); 9528 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9529 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9530 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9531 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9532 PetscCall(VecGetDM(cellgeom, &dmCell)); 9533 PetscCall(VecGetDM(facegeom, &dmFace)); 9534 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9535 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9536 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9537 PetscInt cellarr[2], *adj = NULL; 9538 PetscScalar *cArr, *fArr; 9539 PetscReal minvalc = 1.0, minvalf = 1.0; 9540 PetscFVCellGeom *cg; 9541 9542 idx[cellIter] = cell - cStart; 9543 cellarr[0] = cell; 9544 /* Make indexing into cellGeom easier */ 9545 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9546 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9547 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9548 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9549 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9550 PetscInt i; 9551 const PetscInt neigh = adj[cellneigh]; 9552 PetscReal normci = 0, normfi = 0, normai = 0; 9553 PetscFVCellGeom *cgneigh; 9554 PetscFVFaceGeom *fg; 9555 9556 /* Don't count ourselves in the neighbor list */ 9557 if (neigh == cell) continue; 9558 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9559 cellarr[1] = neigh; 9560 { 9561 PetscInt numcovpts; 9562 const PetscInt *covpts; 9563 9564 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9565 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9566 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9567 } 9568 9569 /* Compute c_i, f_i and their norms */ 9570 for (i = 0; i < nc; i++) { 9571 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9572 fi[i] = fg->centroid[i] - cg->centroid[i]; 9573 Ai[i] = fg->normal[i]; 9574 normci += PetscPowReal(ci[i], 2); 9575 normfi += PetscPowReal(fi[i], 2); 9576 normai += PetscPowReal(Ai[i], 2); 9577 } 9578 normci = PetscSqrtReal(normci); 9579 normfi = PetscSqrtReal(normfi); 9580 normai = PetscSqrtReal(normai); 9581 9582 /* Normalize and compute for each face-cell-normal pair */ 9583 for (i = 0; i < nc; i++) { 9584 ci[i] = ci[i] / normci; 9585 fi[i] = fi[i] / normfi; 9586 Ai[i] = Ai[i] / normai; 9587 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9588 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9589 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9590 } 9591 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9592 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9593 } 9594 PetscCall(PetscFree(adj)); 9595 PetscCall(PetscFree2(cArr, fArr)); 9596 /* Defer to cell if they're equal */ 9597 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9598 if (OrthQualLabel) { 9599 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9600 } 9601 } 9602 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9603 PetscCall(VecAssemblyBegin(*OrthQual)); 9604 PetscCall(VecAssemblyEnd(*OrthQual)); 9605 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9606 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9607 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9608 if (OrthQualLabel) { 9609 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9610 } 9611 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9612 PetscCall(PetscViewerDestroy(&vwr)); 9613 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9614 PetscFunctionReturn(PETSC_SUCCESS); 9615 } 9616 9617 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9618 * interpolator construction */ 9619 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9620 { 9621 PetscSection section, newSection, gsection; 9622 PetscSF sf; 9623 PetscBool hasConstraints, ghasConstraints; 9624 9625 PetscFunctionBegin; 9626 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9627 PetscAssertPointer(odm, 2); 9628 PetscCall(DMGetLocalSection(dm, §ion)); 9629 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9630 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9631 if (!ghasConstraints) { 9632 PetscCall(PetscObjectReference((PetscObject)dm)); 9633 *odm = dm; 9634 PetscFunctionReturn(PETSC_SUCCESS); 9635 } 9636 PetscCall(DMClone(dm, odm)); 9637 PetscCall(DMCopyFields(dm, *odm)); 9638 PetscCall(DMGetLocalSection(*odm, &newSection)); 9639 PetscCall(DMGetPointSF(*odm, &sf)); 9640 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9641 PetscCall(DMSetGlobalSection(*odm, gsection)); 9642 PetscCall(PetscSectionDestroy(&gsection)); 9643 PetscFunctionReturn(PETSC_SUCCESS); 9644 } 9645 9646 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9647 { 9648 DM dmco, dmfo; 9649 Mat interpo; 9650 Vec rscale; 9651 Vec cglobalo, clocal; 9652 Vec fglobal, fglobalo, flocal; 9653 PetscBool regular; 9654 9655 PetscFunctionBegin; 9656 PetscCall(DMGetFullDM(dmc, &dmco)); 9657 PetscCall(DMGetFullDM(dmf, &dmfo)); 9658 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9659 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9660 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9661 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9662 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9663 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9664 PetscCall(VecSet(cglobalo, 0.)); 9665 PetscCall(VecSet(clocal, 0.)); 9666 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9667 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9668 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9669 PetscCall(VecSet(fglobal, 0.)); 9670 PetscCall(VecSet(fglobalo, 0.)); 9671 PetscCall(VecSet(flocal, 0.)); 9672 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9673 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9674 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9675 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9676 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9677 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9678 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9679 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9680 *shift = fglobal; 9681 PetscCall(VecDestroy(&flocal)); 9682 PetscCall(VecDestroy(&fglobalo)); 9683 PetscCall(VecDestroy(&clocal)); 9684 PetscCall(VecDestroy(&cglobalo)); 9685 PetscCall(VecDestroy(&rscale)); 9686 PetscCall(MatDestroy(&interpo)); 9687 PetscCall(DMDestroy(&dmfo)); 9688 PetscCall(DMDestroy(&dmco)); 9689 PetscFunctionReturn(PETSC_SUCCESS); 9690 } 9691 9692 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9693 { 9694 PetscObject shifto; 9695 Vec shift; 9696 9697 PetscFunctionBegin; 9698 if (!interp) { 9699 Vec rscale; 9700 9701 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9702 PetscCall(VecDestroy(&rscale)); 9703 } else { 9704 PetscCall(PetscObjectReference((PetscObject)interp)); 9705 } 9706 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9707 if (!shifto) { 9708 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9709 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9710 shifto = (PetscObject)shift; 9711 PetscCall(VecDestroy(&shift)); 9712 } 9713 shift = (Vec)shifto; 9714 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9715 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9716 PetscCall(MatDestroy(&interp)); 9717 PetscFunctionReturn(PETSC_SUCCESS); 9718 } 9719 9720 /* Pointwise interpolation 9721 Just code FEM for now 9722 u^f = I u^c 9723 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9724 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9725 I_{ij} = psi^f_i phi^c_j 9726 */ 9727 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9728 { 9729 PetscSection gsc, gsf; 9730 PetscInt m, n; 9731 void *ctx; 9732 DM cdm; 9733 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9734 9735 PetscFunctionBegin; 9736 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9737 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9738 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9739 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9740 9741 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9742 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9743 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9744 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9745 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9746 9747 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9748 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9749 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9750 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9751 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9752 if (scaling) { 9753 /* Use naive scaling */ 9754 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9755 } 9756 PetscFunctionReturn(PETSC_SUCCESS); 9757 } 9758 9759 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9760 { 9761 VecScatter ctx; 9762 9763 PetscFunctionBegin; 9764 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9765 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9766 PetscCall(VecScatterDestroy(&ctx)); 9767 PetscFunctionReturn(PETSC_SUCCESS); 9768 } 9769 9770 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[]) 9771 { 9772 const PetscInt Nc = uOff[1] - uOff[0]; 9773 PetscInt c; 9774 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9775 } 9776 9777 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9778 { 9779 DM dmc; 9780 PetscDS ds; 9781 Vec ones, locmass; 9782 IS cellIS; 9783 PetscFormKey key; 9784 PetscInt depth; 9785 9786 PetscFunctionBegin; 9787 PetscCall(DMClone(dm, &dmc)); 9788 PetscCall(DMCopyDisc(dm, dmc)); 9789 PetscCall(DMGetDS(dmc, &ds)); 9790 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9791 PetscCall(DMCreateGlobalVector(dmc, mass)); 9792 PetscCall(DMGetLocalVector(dmc, &ones)); 9793 PetscCall(DMGetLocalVector(dmc, &locmass)); 9794 PetscCall(DMPlexGetDepth(dmc, &depth)); 9795 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9796 PetscCall(VecSet(locmass, 0.0)); 9797 PetscCall(VecSet(ones, 1.0)); 9798 key.label = NULL; 9799 key.value = 0; 9800 key.field = 0; 9801 key.part = 0; 9802 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9803 PetscCall(ISDestroy(&cellIS)); 9804 PetscCall(VecSet(*mass, 0.0)); 9805 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9806 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9807 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9808 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9809 PetscCall(DMDestroy(&dmc)); 9810 PetscFunctionReturn(PETSC_SUCCESS); 9811 } 9812 9813 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9814 { 9815 PetscSection gsc, gsf; 9816 PetscInt m, n; 9817 void *ctx; 9818 DM cdm; 9819 PetscBool regular; 9820 9821 PetscFunctionBegin; 9822 if (dmFine == dmCoarse) { 9823 DM dmc; 9824 PetscDS ds; 9825 PetscWeakForm wf; 9826 Vec u; 9827 IS cellIS; 9828 PetscFormKey key; 9829 PetscInt depth; 9830 9831 PetscCall(DMClone(dmFine, &dmc)); 9832 PetscCall(DMCopyDisc(dmFine, dmc)); 9833 PetscCall(DMGetDS(dmc, &ds)); 9834 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9835 PetscCall(PetscWeakFormClear(wf)); 9836 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9837 PetscCall(DMCreateMatrix(dmc, mass)); 9838 PetscCall(DMGetLocalVector(dmc, &u)); 9839 PetscCall(DMPlexGetDepth(dmc, &depth)); 9840 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9841 PetscCall(MatZeroEntries(*mass)); 9842 key.label = NULL; 9843 key.value = 0; 9844 key.field = 0; 9845 key.part = 0; 9846 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9847 PetscCall(ISDestroy(&cellIS)); 9848 PetscCall(DMRestoreLocalVector(dmc, &u)); 9849 PetscCall(DMDestroy(&dmc)); 9850 } else { 9851 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9852 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9853 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9854 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9855 9856 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9857 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9858 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9859 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9860 9861 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9862 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9863 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9864 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9865 } 9866 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9867 PetscFunctionReturn(PETSC_SUCCESS); 9868 } 9869 9870 /*@ 9871 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9872 9873 Input Parameter: 9874 . dm - The `DMPLEX` object 9875 9876 Output Parameter: 9877 . regular - The flag 9878 9879 Level: intermediate 9880 9881 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9882 @*/ 9883 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9884 { 9885 PetscFunctionBegin; 9886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9887 PetscAssertPointer(regular, 2); 9888 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9889 PetscFunctionReturn(PETSC_SUCCESS); 9890 } 9891 9892 /*@ 9893 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9894 9895 Input Parameters: 9896 + dm - The `DMPLEX` object 9897 - regular - The flag 9898 9899 Level: intermediate 9900 9901 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9902 @*/ 9903 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9904 { 9905 PetscFunctionBegin; 9906 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9907 ((DM_Plex *)dm->data)->regularRefinement = regular; 9908 PetscFunctionReturn(PETSC_SUCCESS); 9909 } 9910 9911 /*@ 9912 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9913 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9914 9915 Not Collective 9916 9917 Input Parameter: 9918 . dm - The `DMPLEX` object 9919 9920 Output Parameters: 9921 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9922 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 9923 9924 Level: intermediate 9925 9926 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9927 @*/ 9928 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9929 { 9930 DM_Plex *plex = (DM_Plex *)dm->data; 9931 9932 PetscFunctionBegin; 9933 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9934 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9935 if (anchorSection) *anchorSection = plex->anchorSection; 9936 if (anchorIS) *anchorIS = plex->anchorIS; 9937 PetscFunctionReturn(PETSC_SUCCESS); 9938 } 9939 9940 /*@ 9941 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 9942 9943 Collective 9944 9945 Input Parameters: 9946 + dm - The `DMPLEX` object 9947 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9948 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9949 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9950 9951 Level: intermediate 9952 9953 Notes: 9954 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 9955 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 9956 combination of other points' degrees of freedom. 9957 9958 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9959 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9960 9961 The reference counts of `anchorSection` and `anchorIS` are incremented. 9962 9963 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9964 @*/ 9965 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9966 { 9967 DM_Plex *plex = (DM_Plex *)dm->data; 9968 PetscMPIInt result; 9969 9970 PetscFunctionBegin; 9971 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9972 if (anchorSection) { 9973 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9974 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9975 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9976 } 9977 if (anchorIS) { 9978 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9979 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9980 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9981 } 9982 9983 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9984 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9985 plex->anchorSection = anchorSection; 9986 9987 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9988 PetscCall(ISDestroy(&plex->anchorIS)); 9989 plex->anchorIS = anchorIS; 9990 9991 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9992 PetscInt size, a, pStart, pEnd; 9993 const PetscInt *anchors; 9994 9995 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9996 PetscCall(ISGetLocalSize(anchorIS, &size)); 9997 PetscCall(ISGetIndices(anchorIS, &anchors)); 9998 for (a = 0; a < size; a++) { 9999 PetscInt p; 10000 10001 p = anchors[a]; 10002 if (p >= pStart && p < pEnd) { 10003 PetscInt dof; 10004 10005 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10006 if (dof) { 10007 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10008 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10009 } 10010 } 10011 } 10012 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10013 } 10014 /* reset the generic constraints */ 10015 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10016 PetscFunctionReturn(PETSC_SUCCESS); 10017 } 10018 10019 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10020 { 10021 PetscSection anchorSection; 10022 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10023 10024 PetscFunctionBegin; 10025 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10026 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10027 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10028 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10029 if (numFields) { 10030 PetscInt f; 10031 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10032 10033 for (f = 0; f < numFields; f++) { 10034 PetscInt numComp; 10035 10036 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10037 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10038 } 10039 } 10040 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10041 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10042 pStart = PetscMax(pStart, sStart); 10043 pEnd = PetscMin(pEnd, sEnd); 10044 pEnd = PetscMax(pStart, pEnd); 10045 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10046 for (p = pStart; p < pEnd; p++) { 10047 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10048 if (dof) { 10049 PetscCall(PetscSectionGetDof(section, p, &dof)); 10050 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10051 for (f = 0; f < numFields; f++) { 10052 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10053 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10054 } 10055 } 10056 } 10057 PetscCall(PetscSectionSetUp(*cSec)); 10058 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10059 PetscFunctionReturn(PETSC_SUCCESS); 10060 } 10061 10062 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10063 { 10064 PetscSection aSec; 10065 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10066 const PetscInt *anchors; 10067 PetscInt numFields, f; 10068 IS aIS; 10069 MatType mtype; 10070 PetscBool iscuda, iskokkos; 10071 10072 PetscFunctionBegin; 10073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10074 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10075 PetscCall(PetscSectionGetStorageSize(section, &n)); 10076 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10077 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10078 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10079 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10080 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10081 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10082 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10083 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10084 else mtype = MATSEQAIJ; 10085 PetscCall(MatSetType(*cMat, mtype)); 10086 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10087 PetscCall(ISGetIndices(aIS, &anchors)); 10088 /* cSec will be a subset of aSec and section */ 10089 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10090 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10091 PetscCall(PetscMalloc1(m + 1, &i)); 10092 i[0] = 0; 10093 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10094 for (p = pStart; p < pEnd; p++) { 10095 PetscInt rDof, rOff, r; 10096 10097 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10098 if (!rDof) continue; 10099 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10100 if (numFields) { 10101 for (f = 0; f < numFields; f++) { 10102 annz = 0; 10103 for (r = 0; r < rDof; r++) { 10104 a = anchors[rOff + r]; 10105 if (a < sStart || a >= sEnd) continue; 10106 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10107 annz += aDof; 10108 } 10109 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10110 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10111 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10112 } 10113 } else { 10114 annz = 0; 10115 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10116 for (q = 0; q < dof; q++) { 10117 a = anchors[rOff + q]; 10118 if (a < sStart || a >= sEnd) continue; 10119 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10120 annz += aDof; 10121 } 10122 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10123 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10124 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10125 } 10126 } 10127 nnz = i[m]; 10128 PetscCall(PetscMalloc1(nnz, &j)); 10129 offset = 0; 10130 for (p = pStart; p < pEnd; p++) { 10131 if (numFields) { 10132 for (f = 0; f < numFields; f++) { 10133 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10134 for (q = 0; q < dof; q++) { 10135 PetscInt rDof, rOff, r; 10136 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10137 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10138 for (r = 0; r < rDof; r++) { 10139 PetscInt s; 10140 10141 a = anchors[rOff + r]; 10142 if (a < sStart || a >= sEnd) continue; 10143 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10144 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10145 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10146 } 10147 } 10148 } 10149 } else { 10150 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10151 for (q = 0; q < dof; q++) { 10152 PetscInt rDof, rOff, r; 10153 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10154 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10155 for (r = 0; r < rDof; r++) { 10156 PetscInt s; 10157 10158 a = anchors[rOff + r]; 10159 if (a < sStart || a >= sEnd) continue; 10160 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10161 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10162 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10163 } 10164 } 10165 } 10166 } 10167 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10168 PetscCall(PetscFree(i)); 10169 PetscCall(PetscFree(j)); 10170 PetscCall(ISRestoreIndices(aIS, &anchors)); 10171 PetscFunctionReturn(PETSC_SUCCESS); 10172 } 10173 10174 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10175 { 10176 DM_Plex *plex = (DM_Plex *)dm->data; 10177 PetscSection anchorSection, section, cSec; 10178 Mat cMat; 10179 10180 PetscFunctionBegin; 10181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10182 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10183 if (anchorSection) { 10184 PetscInt Nf; 10185 10186 PetscCall(DMGetLocalSection(dm, §ion)); 10187 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10188 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10189 PetscCall(DMGetNumFields(dm, &Nf)); 10190 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10191 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10192 PetscCall(PetscSectionDestroy(&cSec)); 10193 PetscCall(MatDestroy(&cMat)); 10194 } 10195 PetscFunctionReturn(PETSC_SUCCESS); 10196 } 10197 10198 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10199 { 10200 IS subis; 10201 PetscSection section, subsection; 10202 10203 PetscFunctionBegin; 10204 PetscCall(DMGetLocalSection(dm, §ion)); 10205 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10206 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10207 /* Create subdomain */ 10208 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10209 /* Create submodel */ 10210 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10211 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10212 PetscCall(DMSetLocalSection(*subdm, subsection)); 10213 PetscCall(PetscSectionDestroy(&subsection)); 10214 PetscCall(DMCopyDisc(dm, *subdm)); 10215 /* Create map from submodel to global model */ 10216 if (is) { 10217 PetscSection sectionGlobal, subsectionGlobal; 10218 IS spIS; 10219 const PetscInt *spmap; 10220 PetscInt *subIndices; 10221 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10222 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10223 10224 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10225 PetscCall(ISGetIndices(spIS, &spmap)); 10226 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10227 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10228 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10229 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10230 for (p = pStart; p < pEnd; ++p) { 10231 PetscInt gdof, pSubSize = 0; 10232 10233 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10234 if (gdof > 0) { 10235 for (f = 0; f < Nf; ++f) { 10236 PetscInt fdof, fcdof; 10237 10238 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10239 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10240 pSubSize += fdof - fcdof; 10241 } 10242 subSize += pSubSize; 10243 if (pSubSize) { 10244 if (bs < 0) { 10245 bs = pSubSize; 10246 } else if (bs != pSubSize) { 10247 /* Layout does not admit a pointwise block size */ 10248 bs = 1; 10249 } 10250 } 10251 } 10252 } 10253 /* Must have same blocksize on all procs (some might have no points) */ 10254 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10255 bsLocal[1] = bs; 10256 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10257 if (bsMinMax[0] != bsMinMax[1]) { 10258 bs = 1; 10259 } else { 10260 bs = bsMinMax[0]; 10261 } 10262 PetscCall(PetscMalloc1(subSize, &subIndices)); 10263 for (p = pStart; p < pEnd; ++p) { 10264 PetscInt gdof, goff; 10265 10266 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10267 if (gdof > 0) { 10268 const PetscInt point = spmap[p]; 10269 10270 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10271 for (f = 0; f < Nf; ++f) { 10272 PetscInt fdof, fcdof, fc, f2, poff = 0; 10273 10274 /* Can get rid of this loop by storing field information in the global section */ 10275 for (f2 = 0; f2 < f; ++f2) { 10276 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10277 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10278 poff += fdof - fcdof; 10279 } 10280 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10281 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10282 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10283 } 10284 } 10285 } 10286 PetscCall(ISRestoreIndices(spIS, &spmap)); 10287 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10288 if (bs > 1) { 10289 /* We need to check that the block size does not come from non-contiguous fields */ 10290 PetscInt i, j, set = 1; 10291 for (i = 0; i < subSize; i += bs) { 10292 for (j = 0; j < bs; ++j) { 10293 if (subIndices[i + j] != subIndices[i] + j) { 10294 set = 0; 10295 break; 10296 } 10297 } 10298 } 10299 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10300 } 10301 /* Attach nullspace */ 10302 for (f = 0; f < Nf; ++f) { 10303 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10304 if ((*subdm)->nullspaceConstructors[f]) break; 10305 } 10306 if (f < Nf) { 10307 MatNullSpace nullSpace; 10308 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10309 10310 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10311 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10312 } 10313 } 10314 PetscFunctionReturn(PETSC_SUCCESS); 10315 } 10316 10317 /*@ 10318 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10319 10320 Input Parameters: 10321 + dm - The `DM` 10322 - dummy - unused argument 10323 10324 Options Database Key: 10325 . -dm_plex_monitor_throughput - Activate the monitor 10326 10327 Level: developer 10328 10329 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10330 @*/ 10331 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10332 { 10333 PetscLogHandler default_handler; 10334 10335 PetscFunctionBegin; 10336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10337 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10338 if (default_handler) { 10339 PetscLogEvent event; 10340 PetscEventPerfInfo eventInfo; 10341 PetscReal cellRate, flopRate; 10342 PetscInt cStart, cEnd, Nf, N; 10343 const char *name; 10344 10345 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10346 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10347 PetscCall(DMGetNumFields(dm, &Nf)); 10348 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10349 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10350 N = (cEnd - cStart) * Nf * eventInfo.count; 10351 flopRate = eventInfo.flops / eventInfo.time; 10352 cellRate = N / eventInfo.time; 10353 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))); 10354 } else { 10355 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."); 10356 } 10357 PetscFunctionReturn(PETSC_SUCCESS); 10358 } 10359