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