1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 15 16 PetscBool Plexcite = PETSC_FALSE; 17 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 18 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 19 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 20 "journal = {SIAM Journal on Scientific Computing},\n" 21 "volume = {38},\n" 22 "number = {5},\n" 23 "pages = {S143--S155},\n" 24 "eprint = {http://arxiv.org/abs/1506.07749},\n" 25 "doi = {10.1137/15M1026092},\n" 26 "year = {2016},\n" 27 "petsc_uses={DMPlex},\n}\n"; 28 29 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 30 31 /*@ 32 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 33 34 Input Parameter: 35 . dm - The `DMPLEX` object 36 37 Output Parameter: 38 . simplex - Flag checking for a simplex 39 40 Level: intermediate 41 42 Note: 43 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 44 If the mesh has no cells, this returns `PETSC_FALSE`. 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 47 @*/ 48 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 49 { 50 DMPolytopeType ct; 51 PetscInt cStart, cEnd; 52 53 PetscFunctionBegin; 54 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 55 if (cEnd <= cStart) { 56 *simplex = PETSC_FALSE; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 60 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@ 65 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 66 67 Input Parameters: 68 + dm - The `DMPLEX` object 69 - height - The cell height in the Plex, 0 is the default 70 71 Output Parameters: 72 + cStart - The first "normal" cell 73 - cEnd - The upper bound on "normal" cells 74 75 Level: developer 76 77 Note: 78 This function requires that tensor cells are ordered last. 79 80 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 81 @*/ 82 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 83 { 84 DMLabel ctLabel; 85 IS valueIS; 86 const PetscInt *ctypes; 87 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 88 89 PetscFunctionBegin; 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 92 PetscCall(ISGetLocalSize(valueIS, &Nct)); 93 PetscCall(ISGetIndices(valueIS, &ctypes)); 94 if (!Nct) cS = cE = 0; 95 for (PetscInt t = 0; t < Nct; ++t) { 96 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 97 PetscInt ctS, ctE, ht; 98 99 if (ct == DM_POLYTOPE_UNKNOWN) { 100 // If any cells are not typed, just use all cells 101 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 102 break; 103 } 104 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 105 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 106 if (ctS >= ctE) continue; 107 // Check that a point has the right height 108 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 109 if (ht != height) continue; 110 cS = PetscMin(cS, ctS); 111 cE = PetscMax(cE, ctE); 112 } 113 PetscCall(ISDestroy(&valueIS)); 114 // Reset label for fast lookup 115 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 116 if (cStart) *cStart = cS; 117 if (cEnd) *cEnd = cE; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 122 { 123 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 124 PetscInt *sStart, *sEnd; 125 PetscViewerVTKFieldType *ft; 126 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 127 DMLabel depthLabel, ctLabel; 128 129 PetscFunctionBegin; 130 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 131 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 132 PetscCall(DMGetCoordinateDim(dm, &cdim)); 133 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 134 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 135 if (field >= 0) { 136 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 137 } else { 138 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 139 } 140 141 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 142 PetscCall(DMPlexGetDepth(dm, &depth)); 143 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 144 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 145 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 146 const DMPolytopeType ict = (DMPolytopeType)c; 147 PetscInt dep; 148 149 if (ict == DM_POLYTOPE_FV_GHOST) continue; 150 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 151 if (pStart >= 0) { 152 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 153 if (dep != depth - cellHeight) continue; 154 } 155 if (field >= 0) { 156 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 157 } else { 158 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 159 } 160 } 161 162 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 163 *types = 0; 164 165 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 166 if (globalvcdof[c]) ++(*types); 167 } 168 169 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 170 t = 0; 171 if (globalvcdof[DM_NUM_POLYTOPES]) { 172 sStart[t] = vStart; 173 sEnd[t] = vEnd; 174 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 175 ++t; 176 } 177 178 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 179 if (globalvcdof[c]) { 180 const DMPolytopeType ict = (DMPolytopeType)c; 181 182 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 183 sStart[t] = cStart; 184 sEnd[t] = cEnd; 185 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 186 ++t; 187 } 188 } 189 190 if (!*types) { 191 if (field >= 0) { 192 const char *fieldname; 193 194 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 195 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 196 } else { 197 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 198 } 199 } 200 201 *ssStart = sStart; 202 *ssEnd = sEnd; 203 *sft = ft; 204 PetscFunctionReturn(PETSC_SUCCESS); 205 } 206 207 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 208 { 209 PetscFunctionBegin; 210 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 211 PetscFunctionReturn(PETSC_SUCCESS); 212 } 213 214 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 215 { 216 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 217 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 218 219 PetscFunctionBegin; 220 *ft = PETSC_VTK_INVALID; 221 PetscCall(DMGetCoordinateDim(dm, &cdim)); 222 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 223 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 224 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 225 if (field >= 0) { 226 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 227 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 228 } else { 229 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 230 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 231 } 232 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 233 if (globalvcdof[0]) { 234 *sStart = vStart; 235 *sEnd = vEnd; 236 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 237 else *ft = PETSC_VTK_POINT_FIELD; 238 } else if (globalvcdof[1]) { 239 *sStart = cStart; 240 *sEnd = cEnd; 241 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 242 else *ft = PETSC_VTK_CELL_FIELD; 243 } else { 244 if (field >= 0) { 245 const char *fieldname; 246 247 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 248 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 249 } else { 250 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 251 } 252 } 253 PetscFunctionReturn(PETSC_SUCCESS); 254 } 255 256 /*@ 257 DMPlexVecView1D - Plot many 1D solutions on the same line graph 258 259 Collective 260 261 Input Parameters: 262 + dm - The `DMPLEX` object 263 . n - The number of vectors 264 . u - The array of local vectors 265 - viewer - The `PetscViewer` 266 267 Level: advanced 268 269 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 270 @*/ 271 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 272 { 273 PetscDS ds; 274 PetscDraw draw = NULL; 275 PetscDrawLG lg; 276 Vec coordinates; 277 const PetscScalar *coords, **sol; 278 PetscReal *vals; 279 PetscInt *Nc; 280 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 281 char **names; 282 283 PetscFunctionBegin; 284 PetscCall(DMGetDS(dm, &ds)); 285 PetscCall(PetscDSGetNumFields(ds, &Nf)); 286 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 287 PetscCall(PetscDSGetComponents(ds, &Nc)); 288 289 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 290 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 291 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 292 293 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 294 for (i = 0, l = 0; i < n; ++i) { 295 const char *vname; 296 297 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 298 for (f = 0; f < Nf; ++f) { 299 PetscObject disc; 300 const char *fname; 301 char tmpname[PETSC_MAX_PATH_LEN]; 302 303 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 304 /* TODO Create names for components */ 305 for (c = 0; c < Nc[f]; ++c, ++l) { 306 PetscCall(PetscObjectGetName(disc, &fname)); 307 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 308 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 309 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 310 PetscCall(PetscStrallocpy(tmpname, &names[l])); 311 } 312 } 313 } 314 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 315 /* Just add P_1 support for now */ 316 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 317 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 318 PetscCall(VecGetArrayRead(coordinates, &coords)); 319 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 320 for (v = vStart; v < vEnd; ++v) { 321 PetscScalar *x, *svals; 322 323 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 324 for (i = 0; i < n; ++i) { 325 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 326 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 327 } 328 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 329 } 330 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 331 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 332 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 333 PetscCall(PetscFree3(sol, names, vals)); 334 335 PetscCall(PetscDrawLGDraw(lg)); 336 PetscCall(PetscDrawLGDestroy(&lg)); 337 PetscFunctionReturn(PETSC_SUCCESS); 338 } 339 340 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 341 { 342 DM dm; 343 344 PetscFunctionBegin; 345 PetscCall(VecGetDM(u, &dm)); 346 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 347 PetscFunctionReturn(PETSC_SUCCESS); 348 } 349 350 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 351 { 352 DM dm; 353 PetscSection s; 354 PetscDraw draw, popup; 355 DM cdm; 356 PetscSection coordSection; 357 Vec coordinates; 358 const PetscScalar *array; 359 PetscReal lbound[3], ubound[3]; 360 PetscReal vbound[2], time; 361 PetscBool flg; 362 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 363 const char *name; 364 char title[PETSC_MAX_PATH_LEN]; 365 366 PetscFunctionBegin; 367 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 368 PetscCall(VecGetDM(v, &dm)); 369 PetscCall(DMGetCoordinateDim(dm, &dim)); 370 PetscCall(DMGetLocalSection(dm, &s)); 371 PetscCall(PetscSectionGetNumFields(s, &Nf)); 372 PetscCall(DMGetCoarsenLevel(dm, &level)); 373 PetscCall(DMGetCoordinateDM(dm, &cdm)); 374 PetscCall(DMGetLocalSection(cdm, &coordSection)); 375 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 376 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 377 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 378 379 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 380 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 381 382 PetscCall(VecGetLocalSize(coordinates, &N)); 383 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 384 PetscCall(PetscDrawClear(draw)); 385 386 /* Could implement something like DMDASelectFields() */ 387 for (f = 0; f < Nf; ++f) { 388 DM fdm = dm; 389 Vec fv = v; 390 IS fis; 391 char prefix[PETSC_MAX_PATH_LEN]; 392 const char *fname; 393 394 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 395 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 396 397 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 398 else prefix[0] = '\0'; 399 if (Nf > 1) { 400 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 401 PetscCall(VecGetSubVector(v, fis, &fv)); 402 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 403 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 404 } 405 for (comp = 0; comp < Nc; ++comp, ++w) { 406 PetscInt nmax = 2; 407 408 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 409 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 410 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 411 PetscCall(PetscDrawSetTitle(draw, title)); 412 413 /* TODO Get max and min only for this component */ 414 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 415 if (!flg) { 416 PetscCall(VecMin(fv, NULL, &vbound[0])); 417 PetscCall(VecMax(fv, NULL, &vbound[1])); 418 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 419 } 420 421 PetscCall(PetscDrawGetPopup(draw, &popup)); 422 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 423 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 424 PetscCall(VecGetArrayRead(fv, &array)); 425 for (c = cStart; c < cEnd; ++c) { 426 PetscScalar *coords = NULL, *a = NULL; 427 const PetscScalar *coords_arr; 428 PetscBool isDG; 429 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 430 431 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 432 if (a) { 433 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 434 color[1] = color[2] = color[3] = color[0]; 435 } else { 436 PetscScalar *vals = NULL; 437 PetscInt numVals, va; 438 439 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 440 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); 441 switch (numVals / Nc) { 442 case 3: /* P1 Triangle */ 443 case 4: /* P1 Quadrangle */ 444 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 445 break; 446 case 6: /* P2 Triangle */ 447 case 8: /* P2 Quadrangle */ 448 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 449 break; 450 default: 451 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 452 } 453 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 454 } 455 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 456 switch (numCoords) { 457 case 6: 458 case 12: /* Localized triangle */ 459 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])); 460 break; 461 case 8: 462 case 16: /* Localized quadrilateral */ 463 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])); 464 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])); 465 break; 466 default: 467 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 468 } 469 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 470 } 471 PetscCall(VecRestoreArrayRead(fv, &array)); 472 PetscCall(PetscDrawFlush(draw)); 473 PetscCall(PetscDrawPause(draw)); 474 PetscCall(PetscDrawSave(draw)); 475 } 476 if (Nf > 1) { 477 PetscCall(VecRestoreSubVector(v, fis, &fv)); 478 PetscCall(ISDestroy(&fis)); 479 PetscCall(DMDestroy(&fdm)); 480 } 481 } 482 PetscFunctionReturn(PETSC_SUCCESS); 483 } 484 485 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 486 { 487 DM dm; 488 PetscDraw draw; 489 PetscInt dim; 490 PetscBool isnull; 491 492 PetscFunctionBegin; 493 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 494 PetscCall(PetscDrawIsNull(draw, &isnull)); 495 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 496 497 PetscCall(VecGetDM(v, &dm)); 498 PetscCall(DMGetCoordinateDim(dm, &dim)); 499 switch (dim) { 500 case 1: 501 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 502 break; 503 case 2: 504 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 505 break; 506 default: 507 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 508 } 509 PetscFunctionReturn(PETSC_SUCCESS); 510 } 511 512 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 513 { 514 DM dm; 515 Vec locv; 516 const char *name; 517 PetscSection section; 518 PetscInt pStart, pEnd; 519 PetscInt numFields; 520 PetscViewerVTKFieldType ft; 521 522 PetscFunctionBegin; 523 PetscCall(VecGetDM(v, &dm)); 524 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 525 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 526 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 527 PetscCall(VecCopy(v, locv)); 528 PetscCall(DMGetLocalSection(dm, §ion)); 529 PetscCall(PetscSectionGetNumFields(section, &numFields)); 530 if (!numFields) { 531 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 532 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 533 } else { 534 PetscInt f; 535 536 for (f = 0; f < numFields; f++) { 537 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 538 if (ft == PETSC_VTK_INVALID) continue; 539 PetscCall(PetscObjectReference((PetscObject)locv)); 540 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 541 } 542 PetscCall(VecDestroy(&locv)); 543 } 544 PetscFunctionReturn(PETSC_SUCCESS); 545 } 546 547 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 548 { 549 DM dm; 550 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 551 552 PetscFunctionBegin; 553 PetscCall(VecGetDM(v, &dm)); 554 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 555 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 556 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 560 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 561 PetscInt i, numFields; 562 PetscObject fe; 563 PetscBool fem = PETSC_FALSE; 564 Vec locv = v; 565 const char *name; 566 PetscInt step; 567 PetscReal time; 568 569 PetscCall(DMGetNumFields(dm, &numFields)); 570 for (i = 0; i < numFields; i++) { 571 PetscCall(DMGetField(dm, i, NULL, &fe)); 572 if (fe->classid == PETSCFE_CLASSID) { 573 fem = PETSC_TRUE; 574 break; 575 } 576 } 577 if (fem) { 578 PetscObject isZero; 579 580 PetscCall(DMGetLocalVector(dm, &locv)); 581 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 582 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 583 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 584 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 585 PetscCall(VecCopy(v, locv)); 586 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 587 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 588 } 589 if (isvtk) { 590 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 591 } else if (ishdf5) { 592 #if defined(PETSC_HAVE_HDF5) 593 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 594 #else 595 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 596 #endif 597 } else if (isdraw) { 598 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 599 } else if (isglvis) { 600 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 601 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 602 PetscCall(VecView_GLVis(locv, viewer)); 603 } else if (iscgns) { 604 #if defined(PETSC_HAVE_CGNS) 605 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 606 #else 607 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 608 #endif 609 } 610 if (fem) { 611 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 612 PetscCall(DMRestoreLocalVector(dm, &locv)); 613 } 614 } else { 615 PetscBool isseq; 616 617 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 618 if (isseq) PetscCall(VecView_Seq(v, viewer)); 619 else PetscCall(VecView_MPI(v, viewer)); 620 } 621 PetscFunctionReturn(PETSC_SUCCESS); 622 } 623 624 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 625 { 626 DM dm; 627 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 628 629 PetscFunctionBegin; 630 PetscCall(VecGetDM(v, &dm)); 631 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 632 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 633 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 638 if (isvtk || isdraw || isglvis || iscgns) { 639 Vec locv; 640 PetscObject isZero; 641 const char *name; 642 643 PetscCall(DMGetLocalVector(dm, &locv)); 644 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 645 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 646 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 647 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 648 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 649 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 650 PetscCall(VecView_Plex_Local(locv, viewer)); 651 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 652 PetscCall(DMRestoreLocalVector(dm, &locv)); 653 } else if (ishdf5) { 654 #if defined(PETSC_HAVE_HDF5) 655 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 656 #else 657 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 658 #endif 659 } else if (isexodusii) { 660 #if defined(PETSC_HAVE_EXODUSII) 661 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 662 #else 663 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 664 #endif 665 } else { 666 PetscBool isseq; 667 668 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 669 if (isseq) PetscCall(VecView_Seq(v, viewer)); 670 else PetscCall(VecView_MPI(v, viewer)); 671 } 672 PetscFunctionReturn(PETSC_SUCCESS); 673 } 674 675 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 676 { 677 DM dm; 678 MPI_Comm comm; 679 PetscViewerFormat format; 680 Vec v; 681 PetscBool isvtk, ishdf5; 682 683 PetscFunctionBegin; 684 PetscCall(VecGetDM(originalv, &dm)); 685 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 686 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 687 PetscCall(PetscViewerGetFormat(viewer, &format)); 688 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 689 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 690 if (format == PETSC_VIEWER_NATIVE) { 691 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 692 /* this need a better fix */ 693 if (dm->useNatural) { 694 if (dm->sfNatural) { 695 const char *vecname; 696 PetscInt n, nroots; 697 698 PetscCall(VecGetLocalSize(originalv, &n)); 699 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 700 if (n == nroots) { 701 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 702 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 703 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 704 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 705 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 706 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 707 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 708 } else v = originalv; 709 } else v = originalv; 710 711 if (ishdf5) { 712 #if defined(PETSC_HAVE_HDF5) 713 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 714 #else 715 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 716 #endif 717 } else if (isvtk) { 718 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 719 } else { 720 PetscBool isseq; 721 722 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 723 if (isseq) PetscCall(VecView_Seq(v, viewer)); 724 else PetscCall(VecView_MPI(v, viewer)); 725 } 726 if (v != originalv) PetscCall(VecDestroy(&v)); 727 PetscFunctionReturn(PETSC_SUCCESS); 728 } 729 730 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 731 { 732 DM dm; 733 PetscBool ishdf5; 734 735 PetscFunctionBegin; 736 PetscCall(VecGetDM(v, &dm)); 737 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 738 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 739 if (ishdf5) { 740 DM dmBC; 741 Vec gv; 742 const char *name; 743 744 PetscCall(DMGetOutputDM(dm, &dmBC)); 745 PetscCall(DMGetGlobalVector(dmBC, &gv)); 746 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 747 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 748 PetscCall(VecLoad_Default(gv, viewer)); 749 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 750 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 751 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 752 } else PetscCall(VecLoad_Default(v, viewer)); 753 PetscFunctionReturn(PETSC_SUCCESS); 754 } 755 756 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 757 { 758 DM dm; 759 PetscBool ishdf5, isexodusii; 760 761 PetscFunctionBegin; 762 PetscCall(VecGetDM(v, &dm)); 763 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 764 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 765 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 766 if (ishdf5) { 767 #if defined(PETSC_HAVE_HDF5) 768 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 769 #else 770 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 771 #endif 772 } else if (isexodusii) { 773 #if defined(PETSC_HAVE_EXODUSII) 774 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 775 #else 776 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 777 #endif 778 } else PetscCall(VecLoad_Default(v, viewer)); 779 PetscFunctionReturn(PETSC_SUCCESS); 780 } 781 782 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 783 { 784 DM dm; 785 PetscViewerFormat format; 786 PetscBool ishdf5; 787 788 PetscFunctionBegin; 789 PetscCall(VecGetDM(originalv, &dm)); 790 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 791 PetscCall(PetscViewerGetFormat(viewer, &format)); 792 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 793 if (format == PETSC_VIEWER_NATIVE) { 794 if (dm->useNatural) { 795 if (dm->sfNatural) { 796 if (ishdf5) { 797 #if defined(PETSC_HAVE_HDF5) 798 Vec v; 799 const char *vecname; 800 801 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 802 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 803 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 804 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 805 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 806 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 807 PetscCall(VecDestroy(&v)); 808 #else 809 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 810 #endif 811 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 812 } 813 } else PetscCall(VecLoad_Default(originalv, viewer)); 814 } 815 PetscFunctionReturn(PETSC_SUCCESS); 816 } 817 818 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 819 { 820 PetscSection coordSection; 821 Vec coordinates; 822 DMLabel depthLabel, celltypeLabel; 823 const char *name[4]; 824 const PetscScalar *a; 825 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 826 827 PetscFunctionBegin; 828 PetscCall(DMGetDimension(dm, &dim)); 829 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 830 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 831 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 832 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 833 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 834 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 835 PetscCall(VecGetArrayRead(coordinates, &a)); 836 name[0] = "vertex"; 837 name[1] = "edge"; 838 name[dim - 1] = "face"; 839 name[dim] = "cell"; 840 for (c = cStart; c < cEnd; ++c) { 841 PetscInt *closure = NULL; 842 PetscInt closureSize, cl, ct; 843 844 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 845 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 846 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 847 PetscCall(PetscViewerASCIIPushTab(viewer)); 848 for (cl = 0; cl < closureSize * 2; cl += 2) { 849 PetscInt point = closure[cl], depth, dof, off, d, p; 850 851 if ((point < pStart) || (point >= pEnd)) continue; 852 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 853 if (!dof) continue; 854 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 855 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 856 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 857 for (p = 0; p < dof / dim; ++p) { 858 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 859 for (d = 0; d < dim; ++d) { 860 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 861 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 862 } 863 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 864 } 865 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 866 } 867 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 868 PetscCall(PetscViewerASCIIPopTab(viewer)); 869 } 870 PetscCall(VecRestoreArrayRead(coordinates, &a)); 871 PetscFunctionReturn(PETSC_SUCCESS); 872 } 873 874 typedef enum { 875 CS_CARTESIAN, 876 CS_POLAR, 877 CS_CYLINDRICAL, 878 CS_SPHERICAL 879 } CoordSystem; 880 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 881 882 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 883 { 884 PetscInt i; 885 886 PetscFunctionBegin; 887 if (dim > 3) { 888 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 889 } else { 890 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 891 892 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 893 switch (cs) { 894 case CS_CARTESIAN: 895 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 896 break; 897 case CS_POLAR: 898 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 899 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 900 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 901 break; 902 case CS_CYLINDRICAL: 903 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 904 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 905 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 906 trcoords[2] = coords[2]; 907 break; 908 case CS_SPHERICAL: 909 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 910 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 911 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 912 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 913 break; 914 } 915 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 916 } 917 PetscFunctionReturn(PETSC_SUCCESS); 918 } 919 920 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 921 { 922 DM_Plex *mesh = (DM_Plex *)dm->data; 923 DM cdm, cdmCell; 924 PetscSection coordSection, coordSectionCell; 925 Vec coordinates, coordinatesCell; 926 PetscViewerFormat format; 927 928 PetscFunctionBegin; 929 PetscCall(PetscViewerGetFormat(viewer, &format)); 930 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 931 const char *name; 932 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 933 PetscInt pStart, pEnd, p, numLabels, l; 934 PetscMPIInt rank, size; 935 936 PetscCall(DMGetCoordinateDM(dm, &cdm)); 937 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 938 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 939 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 940 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 941 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 942 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 943 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 944 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 945 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 946 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 947 PetscCall(DMGetDimension(dm, &dim)); 948 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 949 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 950 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 951 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 952 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 953 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 954 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 955 for (p = pStart; p < pEnd; ++p) { 956 PetscInt dof, off, s; 957 958 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 959 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 960 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 961 } 962 PetscCall(PetscViewerFlush(viewer)); 963 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 964 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 965 for (p = pStart; p < pEnd; ++p) { 966 PetscInt dof, off, c; 967 968 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 969 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 970 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])); 971 } 972 PetscCall(PetscViewerFlush(viewer)); 973 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 974 if (coordSection && coordinates) { 975 CoordSystem cs = CS_CARTESIAN; 976 const PetscScalar *array, *arrayCell = NULL; 977 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 978 PetscMPIInt rank; 979 const char *name; 980 981 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 982 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 983 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 984 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 985 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 986 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 987 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 988 pStart = PetscMin(pvStart, pcStart); 989 pEnd = PetscMax(pvEnd, pcEnd); 990 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 991 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 992 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 993 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 994 995 PetscCall(VecGetArrayRead(coordinates, &array)); 996 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 997 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 998 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 999 for (p = pStart; p < pEnd; ++p) { 1000 PetscInt dof, off; 1001 1002 if (p >= pvStart && p < pvEnd) { 1003 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1004 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1005 if (dof) { 1006 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1007 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1008 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1009 } 1010 } 1011 if (cdmCell && p >= pcStart && p < pcEnd) { 1012 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1013 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1014 if (dof) { 1015 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1016 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1017 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1018 } 1019 } 1020 } 1021 PetscCall(PetscViewerFlush(viewer)); 1022 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1023 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1024 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1025 } 1026 PetscCall(DMGetNumLabels(dm, &numLabels)); 1027 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1028 for (l = 0; l < numLabels; ++l) { 1029 DMLabel label; 1030 PetscBool isdepth; 1031 const char *name; 1032 1033 PetscCall(DMGetLabelName(dm, l, &name)); 1034 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1035 if (isdepth) continue; 1036 PetscCall(DMGetLabel(dm, name, &label)); 1037 PetscCall(DMLabelView(label, viewer)); 1038 } 1039 if (size > 1) { 1040 PetscSF sf; 1041 1042 PetscCall(DMGetPointSF(dm, &sf)); 1043 PetscCall(PetscSFView(sf, viewer)); 1044 } 1045 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 1046 PetscCall(PetscViewerFlush(viewer)); 1047 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1048 const char *name, *color; 1049 const char *defcolors[3] = {"gray", "orange", "green"}; 1050 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1051 char lname[PETSC_MAX_PATH_LEN]; 1052 PetscReal scale = 2.0; 1053 PetscReal tikzscale = 1.0; 1054 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1055 double tcoords[3]; 1056 PetscScalar *coords; 1057 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 1058 PetscMPIInt rank, size; 1059 char **names, **colors, **lcolors; 1060 PetscBool flg, lflg; 1061 PetscBT wp = NULL; 1062 PetscInt pEnd, pStart; 1063 1064 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1065 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1066 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1067 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1068 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1069 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1070 PetscCall(DMGetDimension(dm, &dim)); 1071 PetscCall(DMPlexGetDepth(dm, &depth)); 1072 PetscCall(DMGetNumLabels(dm, &numLabels)); 1073 numLabels = PetscMax(numLabels, 10); 1074 numColors = 10; 1075 numLColors = 10; 1076 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1077 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1078 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1079 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1080 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1081 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1082 n = 4; 1083 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1084 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1085 n = 4; 1086 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1087 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1088 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1089 if (!useLabels) numLabels = 0; 1090 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1091 if (!useColors) { 1092 numColors = 3; 1093 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1094 } 1095 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1096 if (!useColors) { 1097 numLColors = 4; 1098 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1099 } 1100 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1101 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1102 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1103 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1104 if (depth < dim) plotEdges = PETSC_FALSE; 1105 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1106 1107 /* filter points with labelvalue != labeldefaultvalue */ 1108 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1109 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1110 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1111 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1112 if (lflg) { 1113 DMLabel lbl; 1114 1115 PetscCall(DMGetLabel(dm, lname, &lbl)); 1116 if (lbl) { 1117 PetscInt val, defval; 1118 1119 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1120 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1121 for (c = pStart; c < pEnd; c++) { 1122 PetscInt *closure = NULL; 1123 PetscInt closureSize; 1124 1125 PetscCall(DMLabelGetValue(lbl, c, &val)); 1126 if (val == defval) continue; 1127 1128 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1129 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1130 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1131 } 1132 } 1133 } 1134 1135 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1136 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1137 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1138 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1139 \\documentclass[tikz]{standalone}\n\n\ 1140 \\usepackage{pgflibraryshapes}\n\ 1141 \\usetikzlibrary{backgrounds}\n\ 1142 \\usetikzlibrary{arrows}\n\ 1143 \\begin{document}\n")); 1144 if (size > 1) { 1145 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1146 for (p = 0; p < size; ++p) { 1147 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1148 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1149 } 1150 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1151 } 1152 if (drawHasse) { 1153 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1154 1155 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1156 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1167 } 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1169 1170 /* Plot vertices */ 1171 PetscCall(VecGetArray(coordinates, &coords)); 1172 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1173 for (v = vStart; v < vEnd; ++v) { 1174 PetscInt off, dof, d; 1175 PetscBool isLabeled = PETSC_FALSE; 1176 1177 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1178 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1179 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1180 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1181 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1182 for (d = 0; d < dof; ++d) { 1183 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1184 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1185 } 1186 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1187 if (dim == 3) { 1188 PetscReal tmp = tcoords[1]; 1189 tcoords[1] = tcoords[2]; 1190 tcoords[2] = -tmp; 1191 } 1192 for (d = 0; d < dof; ++d) { 1193 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1194 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1195 } 1196 if (drawHasse) color = colors[0 % numColors]; 1197 else color = colors[rank % numColors]; 1198 for (l = 0; l < numLabels; ++l) { 1199 PetscInt val; 1200 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1201 if (val >= 0) { 1202 color = lcolors[l % numLColors]; 1203 isLabeled = PETSC_TRUE; 1204 break; 1205 } 1206 } 1207 if (drawNumbers[0]) { 1208 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1209 } else if (drawColors[0]) { 1210 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1211 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1212 } 1213 PetscCall(VecRestoreArray(coordinates, &coords)); 1214 PetscCall(PetscViewerFlush(viewer)); 1215 /* Plot edges */ 1216 if (plotEdges) { 1217 PetscCall(VecGetArray(coordinates, &coords)); 1218 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1219 for (e = eStart; e < eEnd; ++e) { 1220 const PetscInt *cone; 1221 PetscInt coneSize, offA, offB, dof, d; 1222 1223 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1224 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1225 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1226 PetscCall(DMPlexGetCone(dm, e, &cone)); 1227 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1228 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1229 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1230 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1231 for (d = 0; d < dof; ++d) { 1232 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1233 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1234 } 1235 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1236 if (dim == 3) { 1237 PetscReal tmp = tcoords[1]; 1238 tcoords[1] = tcoords[2]; 1239 tcoords[2] = -tmp; 1240 } 1241 for (d = 0; d < dof; ++d) { 1242 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1243 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1244 } 1245 if (drawHasse) color = colors[1 % numColors]; 1246 else color = colors[rank % numColors]; 1247 for (l = 0; l < numLabels; ++l) { 1248 PetscInt val; 1249 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1250 if (val >= 0) { 1251 color = lcolors[l % numLColors]; 1252 break; 1253 } 1254 } 1255 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1256 } 1257 PetscCall(VecRestoreArray(coordinates, &coords)); 1258 PetscCall(PetscViewerFlush(viewer)); 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1260 } 1261 /* Plot cells */ 1262 if (dim == 3 || !drawNumbers[1]) { 1263 for (e = eStart; e < eEnd; ++e) { 1264 const PetscInt *cone; 1265 1266 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1267 color = colors[rank % numColors]; 1268 for (l = 0; l < numLabels; ++l) { 1269 PetscInt val; 1270 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1271 if (val >= 0) { 1272 color = lcolors[l % numLColors]; 1273 break; 1274 } 1275 } 1276 PetscCall(DMPlexGetCone(dm, e, &cone)); 1277 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1278 } 1279 } else { 1280 DMPolytopeType ct; 1281 1282 /* Drawing a 2D polygon */ 1283 for (c = cStart; c < cEnd; ++c) { 1284 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1285 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1286 if (DMPolytopeTypeIsHybrid(ct)) { 1287 const PetscInt *cone; 1288 PetscInt coneSize, e; 1289 1290 PetscCall(DMPlexGetCone(dm, c, &cone)); 1291 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1292 for (e = 0; e < coneSize; ++e) { 1293 const PetscInt *econe; 1294 1295 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1296 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)); 1297 } 1298 } else { 1299 PetscInt *closure = NULL; 1300 PetscInt closureSize, Nv = 0, v; 1301 1302 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1303 for (p = 0; p < closureSize * 2; p += 2) { 1304 const PetscInt point = closure[p]; 1305 1306 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1307 } 1308 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1309 for (v = 0; v <= Nv; ++v) { 1310 const PetscInt vertex = closure[v % Nv]; 1311 1312 if (v > 0) { 1313 if (plotEdges) { 1314 const PetscInt *edge; 1315 PetscInt endpoints[2], ne; 1316 1317 endpoints[0] = closure[v - 1]; 1318 endpoints[1] = vertex; 1319 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1320 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1321 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1322 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1323 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1324 } 1325 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1326 } 1327 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1328 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1329 } 1330 } 1331 } 1332 for (c = cStart; c < cEnd; ++c) { 1333 double ccoords[3] = {0.0, 0.0, 0.0}; 1334 PetscBool isLabeled = PETSC_FALSE; 1335 PetscScalar *cellCoords = NULL; 1336 const PetscScalar *array; 1337 PetscInt numCoords, cdim, d; 1338 PetscBool isDG; 1339 1340 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1341 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1342 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1343 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1344 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1345 for (p = 0; p < numCoords / cdim; ++p) { 1346 for (d = 0; d < cdim; ++d) { 1347 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1348 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1349 } 1350 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1351 if (cdim == 3) { 1352 PetscReal tmp = tcoords[1]; 1353 tcoords[1] = tcoords[2]; 1354 tcoords[2] = -tmp; 1355 } 1356 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1357 } 1358 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1359 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1360 for (d = 0; d < cdim; ++d) { 1361 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1362 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1363 } 1364 if (drawHasse) color = colors[depth % numColors]; 1365 else color = colors[rank % numColors]; 1366 for (l = 0; l < numLabels; ++l) { 1367 PetscInt val; 1368 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1369 if (val >= 0) { 1370 color = lcolors[l % numLColors]; 1371 isLabeled = PETSC_TRUE; 1372 break; 1373 } 1374 } 1375 if (drawNumbers[dim]) { 1376 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1377 } else if (drawColors[dim]) { 1378 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1379 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1380 } 1381 if (drawHasse) { 1382 color = colors[depth % numColors]; 1383 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1384 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1388 1389 color = colors[1 % numColors]; 1390 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1391 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1395 1396 color = colors[0 % numColors]; 1397 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1398 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1402 1403 for (p = pStart; p < pEnd; ++p) { 1404 const PetscInt *cone; 1405 PetscInt coneSize, cp; 1406 1407 PetscCall(DMPlexGetCone(dm, p, &cone)); 1408 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1409 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1410 } 1411 } 1412 PetscCall(PetscViewerFlush(viewer)); 1413 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1414 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1416 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1417 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1418 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1419 PetscCall(PetscFree3(names, colors, lcolors)); 1420 PetscCall(PetscBTDestroy(&wp)); 1421 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1422 Vec cown, acown; 1423 VecScatter sct; 1424 ISLocalToGlobalMapping g2l; 1425 IS gid, acis; 1426 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1427 MPI_Group ggroup, ngroup; 1428 PetscScalar *array, nid; 1429 const PetscInt *idxs; 1430 PetscInt *idxs2, *start, *adjacency, *work; 1431 PetscInt64 lm[3], gm[3]; 1432 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1433 PetscMPIInt d1, d2, rank; 1434 1435 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1436 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1437 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1438 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1439 #endif 1440 if (ncomm != MPI_COMM_NULL) { 1441 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1442 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1443 d1 = 0; 1444 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1445 nid = d2; 1446 PetscCallMPI(MPI_Group_free(&ggroup)); 1447 PetscCallMPI(MPI_Group_free(&ngroup)); 1448 PetscCallMPI(MPI_Comm_free(&ncomm)); 1449 } else nid = 0.0; 1450 1451 /* Get connectivity */ 1452 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1453 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1454 1455 /* filter overlapped local cells */ 1456 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1457 PetscCall(ISGetIndices(gid, &idxs)); 1458 PetscCall(ISGetLocalSize(gid, &cum)); 1459 PetscCall(PetscMalloc1(cum, &idxs2)); 1460 for (c = cStart, cum = 0; c < cEnd; c++) { 1461 if (idxs[c - cStart] < 0) continue; 1462 idxs2[cum++] = idxs[c - cStart]; 1463 } 1464 PetscCall(ISRestoreIndices(gid, &idxs)); 1465 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1466 PetscCall(ISDestroy(&gid)); 1467 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1468 1469 /* support for node-aware cell locality */ 1470 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1471 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1472 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1473 PetscCall(VecGetArray(cown, &array)); 1474 for (c = 0; c < numVertices; c++) array[c] = nid; 1475 PetscCall(VecRestoreArray(cown, &array)); 1476 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1477 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1478 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1479 PetscCall(ISDestroy(&acis)); 1480 PetscCall(VecScatterDestroy(&sct)); 1481 PetscCall(VecDestroy(&cown)); 1482 1483 /* compute edgeCut */ 1484 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1485 PetscCall(PetscMalloc1(cum, &work)); 1486 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1487 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1488 PetscCall(ISDestroy(&gid)); 1489 PetscCall(VecGetArray(acown, &array)); 1490 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1491 PetscInt totl; 1492 1493 totl = start[c + 1] - start[c]; 1494 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1495 for (i = 0; i < totl; i++) { 1496 if (work[i] < 0) { 1497 ect += 1; 1498 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1499 } 1500 } 1501 } 1502 PetscCall(PetscFree(work)); 1503 PetscCall(VecRestoreArray(acown, &array)); 1504 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1505 lm[1] = -numVertices; 1506 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1507 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1508 lm[0] = ect; /* edgeCut */ 1509 lm[1] = ectn; /* node-aware edgeCut */ 1510 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1511 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1512 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1513 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1514 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1515 #else 1516 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1517 #endif 1518 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1519 PetscCall(PetscFree(start)); 1520 PetscCall(PetscFree(adjacency)); 1521 PetscCall(VecDestroy(&acown)); 1522 } else { 1523 const char *name; 1524 PetscInt *sizes, *hybsizes, *ghostsizes; 1525 PetscInt locDepth, depth, cellHeight, dim, d; 1526 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1527 PetscInt numLabels, l, maxSize = 17; 1528 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1529 MPI_Comm comm; 1530 PetscMPIInt size, rank; 1531 1532 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1533 PetscCallMPI(MPI_Comm_size(comm, &size)); 1534 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1535 PetscCall(DMGetDimension(dm, &dim)); 1536 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1537 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1538 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1539 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1540 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1541 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1542 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1543 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1544 gcNum = gcEnd - gcStart; 1545 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1546 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1547 for (d = 0; d <= depth; d++) { 1548 PetscInt Nc[2] = {0, 0}, ict; 1549 1550 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1551 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1552 ict = ct0; 1553 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1554 ct0 = (DMPolytopeType)ict; 1555 for (p = pStart; p < pEnd; ++p) { 1556 DMPolytopeType ct; 1557 1558 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1559 if (ct == ct0) ++Nc[0]; 1560 else ++Nc[1]; 1561 } 1562 if (size < maxSize) { 1563 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1564 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1565 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1566 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1567 for (p = 0; p < size; ++p) { 1568 if (rank == 0) { 1569 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1570 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1571 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1572 } 1573 } 1574 } else { 1575 PetscInt locMinMax[2]; 1576 1577 locMinMax[0] = Nc[0] + Nc[1]; 1578 locMinMax[1] = Nc[0] + Nc[1]; 1579 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1580 locMinMax[0] = Nc[1]; 1581 locMinMax[1] = Nc[1]; 1582 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1583 if (d == depth) { 1584 locMinMax[0] = gcNum; 1585 locMinMax[1] = gcNum; 1586 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1587 } 1588 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1589 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1590 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1591 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1592 } 1593 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1594 } 1595 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1596 { 1597 const PetscReal *maxCell; 1598 const PetscReal *L; 1599 PetscBool localized; 1600 1601 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1602 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1603 if (L || localized) { 1604 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1605 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1606 if (L) { 1607 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1608 for (d = 0; d < dim; ++d) { 1609 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1610 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1611 } 1612 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1613 } 1614 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1615 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1616 } 1617 } 1618 PetscCall(DMGetNumLabels(dm, &numLabels)); 1619 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1620 for (l = 0; l < numLabels; ++l) { 1621 DMLabel label; 1622 const char *name; 1623 IS valueIS; 1624 const PetscInt *values; 1625 PetscInt numValues, v; 1626 1627 PetscCall(DMGetLabelName(dm, l, &name)); 1628 PetscCall(DMGetLabel(dm, name, &label)); 1629 PetscCall(DMLabelGetNumValues(label, &numValues)); 1630 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1631 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1632 PetscCall(ISGetIndices(valueIS, &values)); 1633 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1634 for (v = 0; v < numValues; ++v) { 1635 PetscInt size; 1636 1637 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1638 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1639 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1640 } 1641 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1642 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1643 PetscCall(ISRestoreIndices(valueIS, &values)); 1644 PetscCall(ISDestroy(&valueIS)); 1645 } 1646 { 1647 char **labelNames; 1648 PetscInt Nl = numLabels; 1649 PetscBool flg; 1650 1651 PetscCall(PetscMalloc1(Nl, &labelNames)); 1652 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1653 for (l = 0; l < Nl; ++l) { 1654 DMLabel label; 1655 1656 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1657 if (flg) { 1658 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1659 PetscCall(DMLabelView(label, viewer)); 1660 } 1661 PetscCall(PetscFree(labelNames[l])); 1662 } 1663 PetscCall(PetscFree(labelNames)); 1664 } 1665 /* If no fields are specified, people do not want to see adjacency */ 1666 if (dm->Nf) { 1667 PetscInt f; 1668 1669 for (f = 0; f < dm->Nf; ++f) { 1670 const char *name; 1671 1672 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1673 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1674 PetscCall(PetscViewerASCIIPushTab(viewer)); 1675 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1676 if (dm->fields[f].adjacency[0]) { 1677 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1678 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1679 } else { 1680 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1681 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1682 } 1683 PetscCall(PetscViewerASCIIPopTab(viewer)); 1684 } 1685 } 1686 PetscCall(DMGetCoarseDM(dm, &cdm)); 1687 if (cdm) { 1688 PetscCall(PetscViewerASCIIPushTab(viewer)); 1689 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1690 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1691 PetscCall(PetscViewerASCIIPopTab(viewer)); 1692 } 1693 } 1694 PetscFunctionReturn(PETSC_SUCCESS); 1695 } 1696 1697 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1698 { 1699 DMPolytopeType ct; 1700 PetscMPIInt rank; 1701 PetscInt cdim; 1702 1703 PetscFunctionBegin; 1704 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1705 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1706 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1707 switch (ct) { 1708 case DM_POLYTOPE_SEGMENT: 1709 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1710 switch (cdim) { 1711 case 1: { 1712 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1713 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1714 1715 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1716 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1718 } break; 1719 case 2: { 1720 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1721 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1722 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1723 1724 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1725 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)); 1726 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)); 1727 } break; 1728 default: 1729 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1730 } 1731 break; 1732 case DM_POLYTOPE_TRIANGLE: 1733 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)); 1734 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1735 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1737 break; 1738 case DM_POLYTOPE_QUADRILATERAL: 1739 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)); 1740 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)); 1741 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1742 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1745 break; 1746 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1747 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)); 1748 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)); 1749 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1750 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1753 break; 1754 case DM_POLYTOPE_FV_GHOST: 1755 break; 1756 default: 1757 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1758 } 1759 PetscFunctionReturn(PETSC_SUCCESS); 1760 } 1761 1762 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1763 { 1764 PetscReal centroid[2] = {0., 0.}; 1765 PetscMPIInt rank; 1766 PetscInt fillColor; 1767 1768 PetscFunctionBegin; 1769 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1770 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1771 for (PetscInt v = 0; v < Nv; ++v) { 1772 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1773 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1774 } 1775 for (PetscInt e = 0; e < Nv; ++e) { 1776 refCoords[0] = refVertices[e * 2 + 0]; 1777 refCoords[1] = refVertices[e * 2 + 1]; 1778 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1779 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1780 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1781 } 1782 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1783 for (PetscInt d = 0; d < edgeDiv; ++d) { 1784 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)); 1785 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1786 } 1787 } 1788 PetscFunctionReturn(PETSC_SUCCESS); 1789 } 1790 1791 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1792 { 1793 DMPolytopeType ct; 1794 1795 PetscFunctionBegin; 1796 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1797 switch (ct) { 1798 case DM_POLYTOPE_TRIANGLE: { 1799 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1800 1801 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1802 } break; 1803 case DM_POLYTOPE_QUADRILATERAL: { 1804 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1805 1806 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1807 } break; 1808 default: 1809 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1810 } 1811 PetscFunctionReturn(PETSC_SUCCESS); 1812 } 1813 1814 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1815 { 1816 PetscDraw draw; 1817 DM cdm; 1818 PetscSection coordSection; 1819 Vec coordinates; 1820 PetscReal xyl[3], xyr[3]; 1821 PetscReal *refCoords, *edgeCoords; 1822 PetscBool isnull, drawAffine; 1823 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1824 1825 PetscFunctionBegin; 1826 PetscCall(DMGetCoordinateDim(dm, &dim)); 1827 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1828 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1829 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1830 edgeDiv = cDegree + 1; 1831 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1832 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1833 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1834 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1835 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1836 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1837 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1838 1839 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1840 PetscCall(PetscDrawIsNull(draw, &isnull)); 1841 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1842 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1843 1844 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1845 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1846 PetscCall(PetscDrawClear(draw)); 1847 1848 for (c = cStart; c < cEnd; ++c) { 1849 PetscScalar *coords = NULL; 1850 const PetscScalar *coords_arr; 1851 PetscInt numCoords; 1852 PetscBool isDG; 1853 1854 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1855 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1856 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1857 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1858 } 1859 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1860 PetscCall(PetscDrawFlush(draw)); 1861 PetscCall(PetscDrawPause(draw)); 1862 PetscCall(PetscDrawSave(draw)); 1863 PetscFunctionReturn(PETSC_SUCCESS); 1864 } 1865 1866 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1867 { 1868 DM odm = dm, rdm = dm, cdm; 1869 PetscFE fe; 1870 PetscSpace sp; 1871 PetscClassId id; 1872 PetscInt degree; 1873 PetscBool hoView = PETSC_TRUE; 1874 1875 PetscFunctionBegin; 1876 PetscObjectOptionsBegin((PetscObject)dm); 1877 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1878 PetscOptionsEnd(); 1879 PetscCall(PetscObjectReference((PetscObject)dm)); 1880 *hdm = dm; 1881 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1882 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1883 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1884 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1885 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1886 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1887 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1888 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1889 DM cdm, rcdm; 1890 Mat In; 1891 Vec cl, rcl; 1892 1893 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1894 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1895 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1896 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1897 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1898 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1899 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1900 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1901 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1902 PetscCall(MatMult(In, cl, rcl)); 1903 PetscCall(MatDestroy(&In)); 1904 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1905 PetscCall(DMDestroy(&odm)); 1906 odm = rdm; 1907 } 1908 *hdm = rdm; 1909 PetscFunctionReturn(PETSC_SUCCESS); 1910 } 1911 1912 #if defined(PETSC_HAVE_EXODUSII) 1913 #include <exodusII.h> 1914 #include <petscviewerexodusii.h> 1915 #endif 1916 1917 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1918 { 1919 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1920 char name[PETSC_MAX_PATH_LEN]; 1921 1922 PetscFunctionBegin; 1923 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1924 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1925 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1926 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1927 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1928 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1929 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1930 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1931 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1932 if (iascii) { 1933 PetscViewerFormat format; 1934 PetscCall(PetscViewerGetFormat(viewer, &format)); 1935 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1936 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1937 } else if (ishdf5) { 1938 #if defined(PETSC_HAVE_HDF5) 1939 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1940 #else 1941 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1942 #endif 1943 } else if (isvtk) { 1944 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1945 } else if (isdraw) { 1946 DM hdm; 1947 1948 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1949 PetscCall(DMPlexView_Draw(hdm, viewer)); 1950 PetscCall(DMDestroy(&hdm)); 1951 } else if (isglvis) { 1952 PetscCall(DMPlexView_GLVis(dm, viewer)); 1953 #if defined(PETSC_HAVE_EXODUSII) 1954 } else if (isexodus) { 1955 /* 1956 exodusII requires that all sets be part of exactly one cell set. 1957 If the dm does not have a "Cell Sets" label defined, we create one 1958 with ID 1, containing all cells. 1959 Note that if the Cell Sets label is defined but does not cover all cells, 1960 we may still have a problem. This should probably be checked here or in the viewer; 1961 */ 1962 PetscInt numCS; 1963 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1964 if (!numCS) { 1965 PetscInt cStart, cEnd, c; 1966 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1967 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1968 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1969 } 1970 PetscCall(DMView_PlexExodusII(dm, viewer)); 1971 #endif 1972 #if defined(PETSC_HAVE_CGNS) 1973 } else if (iscgns) { 1974 PetscCall(DMView_PlexCGNS(dm, viewer)); 1975 #endif 1976 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1977 /* Optionally view the partition */ 1978 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1979 if (flg) { 1980 Vec ranks; 1981 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1982 PetscCall(VecView(ranks, viewer)); 1983 PetscCall(VecDestroy(&ranks)); 1984 } 1985 /* Optionally view a label */ 1986 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1987 if (flg) { 1988 DMLabel label; 1989 Vec val; 1990 1991 PetscCall(DMGetLabel(dm, name, &label)); 1992 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1993 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1994 PetscCall(VecView(val, viewer)); 1995 PetscCall(VecDestroy(&val)); 1996 } 1997 PetscFunctionReturn(PETSC_SUCCESS); 1998 } 1999 2000 /*@ 2001 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2002 2003 Collective 2004 2005 Input Parameters: 2006 + dm - The `DM` whose topology is to be saved 2007 - viewer - The `PetscViewer` to save it in 2008 2009 Level: advanced 2010 2011 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2012 @*/ 2013 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2014 { 2015 PetscBool ishdf5; 2016 2017 PetscFunctionBegin; 2018 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2019 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2020 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2021 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2022 if (ishdf5) { 2023 #if defined(PETSC_HAVE_HDF5) 2024 PetscViewerFormat format; 2025 PetscCall(PetscViewerGetFormat(viewer, &format)); 2026 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2027 IS globalPointNumbering; 2028 2029 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2030 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2031 PetscCall(ISDestroy(&globalPointNumbering)); 2032 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2033 #else 2034 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2035 #endif 2036 } 2037 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2038 PetscFunctionReturn(PETSC_SUCCESS); 2039 } 2040 2041 /*@ 2042 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2043 2044 Collective 2045 2046 Input Parameters: 2047 + dm - The `DM` whose coordinates are to be saved 2048 - viewer - The `PetscViewer` for saving 2049 2050 Level: advanced 2051 2052 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2053 @*/ 2054 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2055 { 2056 PetscBool ishdf5; 2057 2058 PetscFunctionBegin; 2059 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2060 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2061 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2062 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2063 if (ishdf5) { 2064 #if defined(PETSC_HAVE_HDF5) 2065 PetscViewerFormat format; 2066 PetscCall(PetscViewerGetFormat(viewer, &format)); 2067 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2068 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2069 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2070 #else 2071 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2072 #endif 2073 } 2074 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2075 PetscFunctionReturn(PETSC_SUCCESS); 2076 } 2077 2078 /*@ 2079 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2080 2081 Collective 2082 2083 Input Parameters: 2084 + dm - The `DM` whose labels are to be saved 2085 - viewer - The `PetscViewer` for saving 2086 2087 Level: advanced 2088 2089 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2090 @*/ 2091 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2092 { 2093 PetscBool ishdf5; 2094 2095 PetscFunctionBegin; 2096 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2097 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2098 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2099 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2100 if (ishdf5) { 2101 #if defined(PETSC_HAVE_HDF5) 2102 IS globalPointNumbering; 2103 PetscViewerFormat format; 2104 2105 PetscCall(PetscViewerGetFormat(viewer, &format)); 2106 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2107 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2108 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2109 PetscCall(ISDestroy(&globalPointNumbering)); 2110 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2111 #else 2112 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2113 #endif 2114 } 2115 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2116 PetscFunctionReturn(PETSC_SUCCESS); 2117 } 2118 2119 /*@ 2120 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2121 2122 Collective 2123 2124 Input Parameters: 2125 + dm - The `DM` that contains the topology on which the section to be saved is defined 2126 . viewer - The `PetscViewer` for saving 2127 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2128 2129 Level: advanced 2130 2131 Notes: 2132 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. 2133 2134 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. 2135 2136 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2137 @*/ 2138 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2139 { 2140 PetscBool ishdf5; 2141 2142 PetscFunctionBegin; 2143 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2144 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2145 if (!sectiondm) sectiondm = dm; 2146 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2147 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2148 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2149 if (ishdf5) { 2150 #if defined(PETSC_HAVE_HDF5) 2151 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2152 #else 2153 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2154 #endif 2155 } 2156 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2157 PetscFunctionReturn(PETSC_SUCCESS); 2158 } 2159 2160 /*@ 2161 DMPlexGlobalVectorView - Saves a global vector 2162 2163 Collective 2164 2165 Input Parameters: 2166 + dm - The `DM` that represents the topology 2167 . viewer - The `PetscViewer` to save data with 2168 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2169 - vec - The global vector to be saved 2170 2171 Level: advanced 2172 2173 Notes: 2174 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. 2175 2176 Calling sequence: 2177 .vb 2178 DMCreate(PETSC_COMM_WORLD, &dm); 2179 DMSetType(dm, DMPLEX); 2180 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2181 DMClone(dm, §iondm); 2182 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2183 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2184 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2185 PetscSectionSetChart(section, pStart, pEnd); 2186 PetscSectionSetUp(section); 2187 DMSetLocalSection(sectiondm, section); 2188 PetscSectionDestroy(§ion); 2189 DMGetGlobalVector(sectiondm, &vec); 2190 PetscObjectSetName((PetscObject)vec, "vec_name"); 2191 DMPlexTopologyView(dm, viewer); 2192 DMPlexSectionView(dm, viewer, sectiondm); 2193 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2194 DMRestoreGlobalVector(sectiondm, &vec); 2195 DMDestroy(§iondm); 2196 DMDestroy(&dm); 2197 .ve 2198 2199 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2200 @*/ 2201 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2202 { 2203 PetscBool ishdf5; 2204 2205 PetscFunctionBegin; 2206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2207 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2208 if (!sectiondm) sectiondm = dm; 2209 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2210 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2211 /* Check consistency */ 2212 { 2213 PetscSection section; 2214 PetscBool includesConstraints; 2215 PetscInt m, m1; 2216 2217 PetscCall(VecGetLocalSize(vec, &m1)); 2218 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2219 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2220 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2221 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2222 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2223 } 2224 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2225 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2226 if (ishdf5) { 2227 #if defined(PETSC_HAVE_HDF5) 2228 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2229 #else 2230 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2231 #endif 2232 } 2233 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2234 PetscFunctionReturn(PETSC_SUCCESS); 2235 } 2236 2237 /*@ 2238 DMPlexLocalVectorView - Saves a local vector 2239 2240 Collective 2241 2242 Input Parameters: 2243 + dm - The `DM` that represents the topology 2244 . viewer - The `PetscViewer` to save data with 2245 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2246 - vec - The local vector to be saved 2247 2248 Level: advanced 2249 2250 Note: 2251 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. 2252 2253 Calling sequence: 2254 .vb 2255 DMCreate(PETSC_COMM_WORLD, &dm); 2256 DMSetType(dm, DMPLEX); 2257 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2258 DMClone(dm, §iondm); 2259 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2260 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2261 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2262 PetscSectionSetChart(section, pStart, pEnd); 2263 PetscSectionSetUp(section); 2264 DMSetLocalSection(sectiondm, section); 2265 DMGetLocalVector(sectiondm, &vec); 2266 PetscObjectSetName((PetscObject)vec, "vec_name"); 2267 DMPlexTopologyView(dm, viewer); 2268 DMPlexSectionView(dm, viewer, sectiondm); 2269 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2270 DMRestoreLocalVector(sectiondm, &vec); 2271 DMDestroy(§iondm); 2272 DMDestroy(&dm); 2273 .ve 2274 2275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2276 @*/ 2277 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2278 { 2279 PetscBool ishdf5; 2280 2281 PetscFunctionBegin; 2282 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2283 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2284 if (!sectiondm) sectiondm = dm; 2285 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2286 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2287 /* Check consistency */ 2288 { 2289 PetscSection section; 2290 PetscBool includesConstraints; 2291 PetscInt m, m1; 2292 2293 PetscCall(VecGetLocalSize(vec, &m1)); 2294 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2295 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2296 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2297 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2298 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2299 } 2300 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2301 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2302 if (ishdf5) { 2303 #if defined(PETSC_HAVE_HDF5) 2304 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2305 #else 2306 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2307 #endif 2308 } 2309 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2310 PetscFunctionReturn(PETSC_SUCCESS); 2311 } 2312 2313 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2314 { 2315 PetscBool ishdf5; 2316 2317 PetscFunctionBegin; 2318 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2319 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2320 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2321 if (ishdf5) { 2322 #if defined(PETSC_HAVE_HDF5) 2323 PetscViewerFormat format; 2324 PetscCall(PetscViewerGetFormat(viewer, &format)); 2325 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2326 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2327 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2328 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2329 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2330 PetscFunctionReturn(PETSC_SUCCESS); 2331 #else 2332 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2333 #endif 2334 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2335 } 2336 2337 /*@ 2338 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2339 2340 Collective 2341 2342 Input Parameters: 2343 + dm - The `DM` into which the topology is loaded 2344 - viewer - The `PetscViewer` for the saved topology 2345 2346 Output Parameter: 2347 . 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 2348 2349 Level: advanced 2350 2351 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2352 `PetscViewer`, `PetscSF` 2353 @*/ 2354 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2355 { 2356 PetscBool ishdf5; 2357 2358 PetscFunctionBegin; 2359 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2360 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2361 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2362 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2363 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2364 if (ishdf5) { 2365 #if defined(PETSC_HAVE_HDF5) 2366 PetscViewerFormat format; 2367 PetscCall(PetscViewerGetFormat(viewer, &format)); 2368 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2369 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2370 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2371 #else 2372 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2373 #endif 2374 } 2375 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2376 PetscFunctionReturn(PETSC_SUCCESS); 2377 } 2378 2379 /*@ 2380 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2381 2382 Collective 2383 2384 Input Parameters: 2385 + dm - The `DM` into which the coordinates are loaded 2386 . viewer - The `PetscViewer` for the saved coordinates 2387 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2388 2389 Level: advanced 2390 2391 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2392 `PetscSF`, `PetscViewer` 2393 @*/ 2394 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2395 { 2396 PetscBool ishdf5; 2397 2398 PetscFunctionBegin; 2399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2400 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2401 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2402 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2403 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2404 if (ishdf5) { 2405 #if defined(PETSC_HAVE_HDF5) 2406 PetscViewerFormat format; 2407 PetscCall(PetscViewerGetFormat(viewer, &format)); 2408 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2409 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2410 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2411 #else 2412 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2413 #endif 2414 } 2415 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2416 PetscFunctionReturn(PETSC_SUCCESS); 2417 } 2418 2419 /*@ 2420 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2421 2422 Collective 2423 2424 Input Parameters: 2425 + dm - The `DM` into which the labels are loaded 2426 . viewer - The `PetscViewer` for the saved labels 2427 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2428 2429 Level: advanced 2430 2431 Note: 2432 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2433 2434 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2435 `PetscSF`, `PetscViewer` 2436 @*/ 2437 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2438 { 2439 PetscBool ishdf5; 2440 2441 PetscFunctionBegin; 2442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2443 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2444 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2445 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2446 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2447 if (ishdf5) { 2448 #if defined(PETSC_HAVE_HDF5) 2449 PetscViewerFormat format; 2450 2451 PetscCall(PetscViewerGetFormat(viewer, &format)); 2452 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2453 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2454 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2455 #else 2456 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2457 #endif 2458 } 2459 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2460 PetscFunctionReturn(PETSC_SUCCESS); 2461 } 2462 2463 /*@ 2464 DMPlexSectionLoad - Loads section into a `DMPLEX` 2465 2466 Collective 2467 2468 Input Parameters: 2469 + dm - The `DM` that represents the topology 2470 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2471 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2472 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2473 2474 Output Parameters: 2475 + 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) 2476 - 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) 2477 2478 Level: advanced 2479 2480 Notes: 2481 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. 2482 2483 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (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. 2484 2485 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. 2486 2487 Example using 2 processes: 2488 .vb 2489 NX (number of points on dm): 4 2490 sectionA : the on-disk section 2491 vecA : a vector associated with sectionA 2492 sectionB : sectiondm's local section constructed in this function 2493 vecB (local) : a vector associated with sectiondm's local section 2494 vecB (global) : a vector associated with sectiondm's global section 2495 2496 rank 0 rank 1 2497 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2498 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2499 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2500 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2501 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2502 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2503 sectionB->atlasDof : 1 0 1 | 1 3 2504 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2505 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2506 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2507 .ve 2508 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2509 2510 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2511 @*/ 2512 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2513 { 2514 PetscBool ishdf5; 2515 2516 PetscFunctionBegin; 2517 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2518 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2519 if (!sectiondm) sectiondm = dm; 2520 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2521 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2522 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2523 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2524 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2525 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2526 if (ishdf5) { 2527 #if defined(PETSC_HAVE_HDF5) 2528 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2529 #else 2530 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2531 #endif 2532 } 2533 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2534 PetscFunctionReturn(PETSC_SUCCESS); 2535 } 2536 2537 /*@ 2538 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2539 2540 Collective 2541 2542 Input Parameters: 2543 + dm - The `DM` that represents the topology 2544 . viewer - The `PetscViewer` that represents the on-disk vector data 2545 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2546 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2547 - vec - The global vector to set values of 2548 2549 Level: advanced 2550 2551 Notes: 2552 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. 2553 2554 Calling sequence: 2555 .vb 2556 DMCreate(PETSC_COMM_WORLD, &dm); 2557 DMSetType(dm, DMPLEX); 2558 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2559 DMPlexTopologyLoad(dm, viewer, &sfX); 2560 DMClone(dm, §iondm); 2561 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2562 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2563 DMGetGlobalVector(sectiondm, &vec); 2564 PetscObjectSetName((PetscObject)vec, "vec_name"); 2565 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2566 DMRestoreGlobalVector(sectiondm, &vec); 2567 PetscSFDestroy(&gsf); 2568 PetscSFDestroy(&sfX); 2569 DMDestroy(§iondm); 2570 DMDestroy(&dm); 2571 .ve 2572 2573 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2574 `PetscSF`, `PetscViewer` 2575 @*/ 2576 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2577 { 2578 PetscBool ishdf5; 2579 2580 PetscFunctionBegin; 2581 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2582 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2583 if (!sectiondm) sectiondm = dm; 2584 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2585 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2586 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2587 /* Check consistency */ 2588 { 2589 PetscSection section; 2590 PetscBool includesConstraints; 2591 PetscInt m, m1; 2592 2593 PetscCall(VecGetLocalSize(vec, &m1)); 2594 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2595 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2596 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2597 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2598 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2599 } 2600 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2601 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2602 if (ishdf5) { 2603 #if defined(PETSC_HAVE_HDF5) 2604 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2605 #else 2606 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2607 #endif 2608 } 2609 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2610 PetscFunctionReturn(PETSC_SUCCESS); 2611 } 2612 2613 /*@ 2614 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2615 2616 Collective 2617 2618 Input Parameters: 2619 + dm - The `DM` that represents the topology 2620 . viewer - The `PetscViewer` that represents the on-disk vector data 2621 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2622 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2623 - vec - The local vector to set values of 2624 2625 Level: advanced 2626 2627 Notes: 2628 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. 2629 2630 Calling sequence: 2631 .vb 2632 DMCreate(PETSC_COMM_WORLD, &dm); 2633 DMSetType(dm, DMPLEX); 2634 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2635 DMPlexTopologyLoad(dm, viewer, &sfX); 2636 DMClone(dm, §iondm); 2637 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2638 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2639 DMGetLocalVector(sectiondm, &vec); 2640 PetscObjectSetName((PetscObject)vec, "vec_name"); 2641 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2642 DMRestoreLocalVector(sectiondm, &vec); 2643 PetscSFDestroy(&lsf); 2644 PetscSFDestroy(&sfX); 2645 DMDestroy(§iondm); 2646 DMDestroy(&dm); 2647 .ve 2648 2649 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2650 `PetscSF`, `PetscViewer` 2651 @*/ 2652 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2653 { 2654 PetscBool ishdf5; 2655 2656 PetscFunctionBegin; 2657 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2658 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2659 if (!sectiondm) sectiondm = dm; 2660 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2661 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2662 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2663 /* Check consistency */ 2664 { 2665 PetscSection section; 2666 PetscBool includesConstraints; 2667 PetscInt m, m1; 2668 2669 PetscCall(VecGetLocalSize(vec, &m1)); 2670 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2671 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2672 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2673 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2674 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2675 } 2676 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2677 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2678 if (ishdf5) { 2679 #if defined(PETSC_HAVE_HDF5) 2680 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2681 #else 2682 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2683 #endif 2684 } 2685 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2686 PetscFunctionReturn(PETSC_SUCCESS); 2687 } 2688 2689 PetscErrorCode DMDestroy_Plex(DM dm) 2690 { 2691 DM_Plex *mesh = (DM_Plex *)dm->data; 2692 2693 PetscFunctionBegin; 2694 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2695 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2696 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2697 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2698 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2699 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2700 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2701 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2702 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2703 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2704 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2705 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2706 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2707 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2708 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2709 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2710 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2711 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2712 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2713 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2714 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2715 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2716 PetscCall(PetscFree(mesh->cones)); 2717 PetscCall(PetscFree(mesh->coneOrientations)); 2718 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2719 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2720 PetscCall(PetscFree(mesh->supports)); 2721 PetscCall(PetscFree(mesh->cellTypes)); 2722 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2723 PetscCall(PetscFree(mesh->tetgenOpts)); 2724 PetscCall(PetscFree(mesh->triangleOpts)); 2725 PetscCall(PetscFree(mesh->transformType)); 2726 PetscCall(PetscFree(mesh->distributionName)); 2727 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2728 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2729 PetscCall(ISDestroy(&mesh->subpointIS)); 2730 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2731 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2732 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2733 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2734 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2735 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2736 PetscCall(ISDestroy(&mesh->anchorIS)); 2737 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2738 PetscCall(PetscFree(mesh->parents)); 2739 PetscCall(PetscFree(mesh->childIDs)); 2740 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2741 PetscCall(PetscFree(mesh->children)); 2742 PetscCall(DMDestroy(&mesh->referenceTree)); 2743 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2744 PetscCall(PetscFree(mesh->neighbors)); 2745 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2746 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2747 PetscCall(PetscFree(mesh)); 2748 PetscFunctionReturn(PETSC_SUCCESS); 2749 } 2750 2751 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2752 { 2753 PetscSection sectionGlobal, sectionLocal; 2754 PetscInt bs = -1, mbs; 2755 PetscInt localSize, localStart = 0; 2756 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2757 MatType mtype; 2758 ISLocalToGlobalMapping ltog; 2759 2760 PetscFunctionBegin; 2761 PetscCall(MatInitializePackage()); 2762 mtype = dm->mattype; 2763 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2764 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2765 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2766 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2767 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2768 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2769 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2770 PetscCall(MatSetType(*J, mtype)); 2771 PetscCall(MatSetFromOptions(*J)); 2772 PetscCall(MatGetBlockSize(*J, &mbs)); 2773 if (mbs > 1) bs = mbs; 2774 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2775 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2776 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2777 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2778 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2779 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2780 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2781 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2782 if (!isShell) { 2783 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2784 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2785 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2786 2787 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2788 2789 PetscCall(PetscCalloc1(localSize, &pblocks)); 2790 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2791 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2792 for (p = pStart; p < pEnd; ++p) { 2793 switch (dm->blocking_type) { 2794 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2795 PetscInt bdof, offset; 2796 2797 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2798 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2799 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2800 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2801 // Signal block concatenation 2802 if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof); 2803 dof = dof < 0 ? -(dof + 1) : dof; 2804 bdof = cdof && (dof - cdof) ? 1 : dof; 2805 if (dof) { 2806 if (bs < 0) { 2807 bs = bdof; 2808 } else if (bs != bdof) { 2809 bs = 1; 2810 } 2811 } 2812 } break; 2813 case DM_BLOCKING_FIELD_NODE: { 2814 for (PetscInt field = 0; field < num_fields; field++) { 2815 PetscInt num_comp, bdof, offset; 2816 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2817 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2818 if (dof < 0) continue; 2819 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2820 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2821 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); 2822 PetscInt num_nodes = dof / num_comp; 2823 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2824 // Handle possibly constant block size (unlikely) 2825 bdof = cdof && (dof - cdof) ? 1 : dof; 2826 if (dof) { 2827 if (bs < 0) { 2828 bs = bdof; 2829 } else if (bs != bdof) { 2830 bs = 1; 2831 } 2832 } 2833 } 2834 } break; 2835 } 2836 } 2837 /* Must have same blocksize on all procs (some might have no points) */ 2838 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2839 bsLocal[1] = bs; 2840 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2841 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2842 else bs = bsMinMax[0]; 2843 bs = PetscMax(1, bs); 2844 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2845 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2846 PetscCall(MatSetBlockSize(*J, bs)); 2847 PetscCall(MatSetUp(*J)); 2848 } else { 2849 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2850 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2851 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2852 } 2853 { // Consolidate blocks 2854 PetscInt nblocks = 0; 2855 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2856 if (pblocks[i] == 0) continue; 2857 // Negative block size indicates the blocks should be concatenated 2858 if (pblocks[i] < 0) { 2859 pblocks[i] = -pblocks[i]; 2860 pblocks[nblocks - 1] += pblocks[i]; 2861 } else { 2862 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2863 } 2864 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]); 2865 } 2866 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2867 } 2868 PetscCall(PetscFree(pblocks)); 2869 } 2870 PetscCall(MatSetDM(*J, dm)); 2871 PetscFunctionReturn(PETSC_SUCCESS); 2872 } 2873 2874 /*@ 2875 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2876 2877 Not Collective 2878 2879 Input Parameter: 2880 . dm - The `DMPLEX` 2881 2882 Output Parameter: 2883 . subsection - The subdomain section 2884 2885 Level: developer 2886 2887 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2888 @*/ 2889 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2890 { 2891 DM_Plex *mesh = (DM_Plex *)dm->data; 2892 2893 PetscFunctionBegin; 2894 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2895 if (!mesh->subdomainSection) { 2896 PetscSection section; 2897 PetscSF sf; 2898 2899 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2900 PetscCall(DMGetLocalSection(dm, §ion)); 2901 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2902 PetscCall(PetscSFDestroy(&sf)); 2903 } 2904 *subsection = mesh->subdomainSection; 2905 PetscFunctionReturn(PETSC_SUCCESS); 2906 } 2907 2908 /*@ 2909 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2910 2911 Not Collective 2912 2913 Input Parameter: 2914 . dm - The `DMPLEX` 2915 2916 Output Parameters: 2917 + pStart - The first mesh point 2918 - pEnd - The upper bound for mesh points 2919 2920 Level: beginner 2921 2922 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2923 @*/ 2924 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2925 { 2926 DM_Plex *mesh = (DM_Plex *)dm->data; 2927 2928 PetscFunctionBegin; 2929 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2930 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2931 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2932 PetscFunctionReturn(PETSC_SUCCESS); 2933 } 2934 2935 /*@ 2936 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2937 2938 Not Collective 2939 2940 Input Parameters: 2941 + dm - The `DMPLEX` 2942 . pStart - The first mesh point 2943 - pEnd - The upper bound for mesh points 2944 2945 Level: beginner 2946 2947 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2948 @*/ 2949 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2950 { 2951 DM_Plex *mesh = (DM_Plex *)dm->data; 2952 2953 PetscFunctionBegin; 2954 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2955 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2956 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2957 PetscCall(PetscFree(mesh->cellTypes)); 2958 PetscFunctionReturn(PETSC_SUCCESS); 2959 } 2960 2961 /*@ 2962 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2963 2964 Not Collective 2965 2966 Input Parameters: 2967 + dm - The `DMPLEX` 2968 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2969 2970 Output Parameter: 2971 . size - The cone size for point `p` 2972 2973 Level: beginner 2974 2975 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2976 @*/ 2977 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2978 { 2979 DM_Plex *mesh = (DM_Plex *)dm->data; 2980 2981 PetscFunctionBegin; 2982 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2983 PetscAssertPointer(size, 3); 2984 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2985 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2986 PetscFunctionReturn(PETSC_SUCCESS); 2987 } 2988 2989 /*@ 2990 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2991 2992 Not Collective 2993 2994 Input Parameters: 2995 + dm - The `DMPLEX` 2996 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2997 - size - The cone size for point `p` 2998 2999 Level: beginner 3000 3001 Note: 3002 This should be called after `DMPlexSetChart()`. 3003 3004 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3005 @*/ 3006 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3007 { 3008 DM_Plex *mesh = (DM_Plex *)dm->data; 3009 3010 PetscFunctionBegin; 3011 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3012 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3013 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3014 PetscFunctionReturn(PETSC_SUCCESS); 3015 } 3016 3017 /*@C 3018 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3019 3020 Not Collective 3021 3022 Input Parameters: 3023 + dm - The `DMPLEX` 3024 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3025 3026 Output Parameter: 3027 . cone - An array of points which are on the in-edges for point `p` 3028 3029 Level: beginner 3030 3031 Fortran Notes: 3032 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3033 `DMPlexRestoreCone()` is not needed/available in C. 3034 3035 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3036 @*/ 3037 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3038 { 3039 DM_Plex *mesh = (DM_Plex *)dm->data; 3040 PetscInt off; 3041 3042 PetscFunctionBegin; 3043 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3044 PetscAssertPointer(cone, 3); 3045 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3046 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3047 PetscFunctionReturn(PETSC_SUCCESS); 3048 } 3049 3050 /*@C 3051 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3052 3053 Not Collective 3054 3055 Input Parameters: 3056 + dm - The `DMPLEX` 3057 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3058 3059 Output Parameters: 3060 + pConesSection - `PetscSection` describing the layout of `pCones` 3061 - pCones - An array of points which are on the in-edges for the point set `p` 3062 3063 Level: intermediate 3064 3065 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3066 @*/ 3067 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3068 { 3069 PetscSection cs, newcs; 3070 PetscInt *cones; 3071 PetscInt *newarr = NULL; 3072 PetscInt n; 3073 3074 PetscFunctionBegin; 3075 PetscCall(DMPlexGetCones(dm, &cones)); 3076 PetscCall(DMPlexGetConeSection(dm, &cs)); 3077 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3078 if (pConesSection) *pConesSection = newcs; 3079 if (pCones) { 3080 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3081 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3082 } 3083 PetscFunctionReturn(PETSC_SUCCESS); 3084 } 3085 3086 /*@ 3087 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3088 3089 Not Collective 3090 3091 Input Parameters: 3092 + dm - The `DMPLEX` 3093 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3094 3095 Output Parameter: 3096 . expandedPoints - An array of vertices recursively expanded from input points 3097 3098 Level: advanced 3099 3100 Notes: 3101 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3102 3103 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3104 3105 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3106 `DMPlexGetDepth()`, `IS` 3107 @*/ 3108 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3109 { 3110 IS *expandedPointsAll; 3111 PetscInt depth; 3112 3113 PetscFunctionBegin; 3114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3115 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3116 PetscAssertPointer(expandedPoints, 3); 3117 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3118 *expandedPoints = expandedPointsAll[0]; 3119 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3120 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3121 PetscFunctionReturn(PETSC_SUCCESS); 3122 } 3123 3124 /*@ 3125 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). 3126 3127 Not Collective 3128 3129 Input Parameters: 3130 + dm - The `DMPLEX` 3131 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3132 3133 Output Parameters: 3134 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3135 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3136 - sections - (optional) An array of sections which describe mappings from points to their cone points 3137 3138 Level: advanced 3139 3140 Notes: 3141 Like `DMPlexGetConeTuple()` but recursive. 3142 3143 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. 3144 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3145 3146 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\: 3147 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3148 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3149 3150 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3151 `DMPlexGetDepth()`, `PetscSection`, `IS` 3152 @*/ 3153 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3154 { 3155 const PetscInt *arr0 = NULL, *cone = NULL; 3156 PetscInt *arr = NULL, *newarr = NULL; 3157 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3158 IS *expandedPoints_; 3159 PetscSection *sections_; 3160 3161 PetscFunctionBegin; 3162 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3163 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3164 if (depth) PetscAssertPointer(depth, 3); 3165 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3166 if (sections) PetscAssertPointer(sections, 5); 3167 PetscCall(ISGetLocalSize(points, &n)); 3168 PetscCall(ISGetIndices(points, &arr0)); 3169 PetscCall(DMPlexGetDepth(dm, &depth_)); 3170 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3171 PetscCall(PetscCalloc1(depth_, §ions_)); 3172 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3173 for (d = depth_ - 1; d >= 0; d--) { 3174 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3175 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3176 for (i = 0; i < n; i++) { 3177 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3178 if (arr[i] >= start && arr[i] < end) { 3179 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3180 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3181 } else { 3182 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3183 } 3184 } 3185 PetscCall(PetscSectionSetUp(sections_[d])); 3186 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3187 PetscCall(PetscMalloc1(newn, &newarr)); 3188 for (i = 0; i < n; i++) { 3189 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3190 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3191 if (cn > 1) { 3192 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3193 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3194 } else { 3195 newarr[co] = arr[i]; 3196 } 3197 } 3198 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3199 arr = newarr; 3200 n = newn; 3201 } 3202 PetscCall(ISRestoreIndices(points, &arr0)); 3203 *depth = depth_; 3204 if (expandedPoints) *expandedPoints = expandedPoints_; 3205 else { 3206 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3207 PetscCall(PetscFree(expandedPoints_)); 3208 } 3209 if (sections) *sections = sections_; 3210 else { 3211 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3212 PetscCall(PetscFree(sections_)); 3213 } 3214 PetscFunctionReturn(PETSC_SUCCESS); 3215 } 3216 3217 /*@ 3218 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3219 3220 Not Collective 3221 3222 Input Parameters: 3223 + dm - The `DMPLEX` 3224 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3225 3226 Output Parameters: 3227 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3228 . expandedPoints - (optional) An array of recursively expanded cones 3229 - sections - (optional) An array of sections which describe mappings from points to their cone points 3230 3231 Level: advanced 3232 3233 Note: 3234 See `DMPlexGetConeRecursive()` 3235 3236 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3237 `DMPlexGetDepth()`, `IS`, `PetscSection` 3238 @*/ 3239 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3240 { 3241 PetscInt d, depth_; 3242 3243 PetscFunctionBegin; 3244 PetscCall(DMPlexGetDepth(dm, &depth_)); 3245 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3246 if (depth) *depth = 0; 3247 if (expandedPoints) { 3248 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3249 PetscCall(PetscFree(*expandedPoints)); 3250 } 3251 if (sections) { 3252 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3253 PetscCall(PetscFree(*sections)); 3254 } 3255 PetscFunctionReturn(PETSC_SUCCESS); 3256 } 3257 3258 /*@ 3259 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 3260 3261 Not Collective 3262 3263 Input Parameters: 3264 + dm - The `DMPLEX` 3265 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3266 - cone - An array of points which are on the in-edges for point `p` 3267 3268 Level: beginner 3269 3270 Note: 3271 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3272 3273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3274 @*/ 3275 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3276 { 3277 DM_Plex *mesh = (DM_Plex *)dm->data; 3278 PetscInt dof, off, c; 3279 3280 PetscFunctionBegin; 3281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3282 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3283 if (dof) PetscAssertPointer(cone, 3); 3284 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3285 if (PetscDefined(USE_DEBUG)) { 3286 PetscInt pStart, pEnd; 3287 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3288 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); 3289 for (c = 0; c < dof; ++c) { 3290 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); 3291 mesh->cones[off + c] = cone[c]; 3292 } 3293 } else { 3294 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3295 } 3296 PetscFunctionReturn(PETSC_SUCCESS); 3297 } 3298 3299 /*@C 3300 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3301 3302 Not Collective 3303 3304 Input Parameters: 3305 + dm - The `DMPLEX` 3306 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3307 3308 Output Parameter: 3309 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3310 integer giving the prescription for cone traversal. 3311 3312 Level: beginner 3313 3314 Note: 3315 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3316 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3317 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3318 with the identity. 3319 3320 Fortran Notes: 3321 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3322 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3323 3324 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3325 @*/ 3326 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3327 { 3328 DM_Plex *mesh = (DM_Plex *)dm->data; 3329 PetscInt off; 3330 3331 PetscFunctionBegin; 3332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3333 if (PetscDefined(USE_DEBUG)) { 3334 PetscInt dof; 3335 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3336 if (dof) PetscAssertPointer(coneOrientation, 3); 3337 } 3338 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3339 3340 *coneOrientation = &mesh->coneOrientations[off]; 3341 PetscFunctionReturn(PETSC_SUCCESS); 3342 } 3343 3344 /*@ 3345 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3346 3347 Not Collective 3348 3349 Input Parameters: 3350 + dm - The `DMPLEX` 3351 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3352 - coneOrientation - An array of orientations 3353 3354 Level: beginner 3355 3356 Notes: 3357 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3358 3359 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3360 3361 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3362 @*/ 3363 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3364 { 3365 DM_Plex *mesh = (DM_Plex *)dm->data; 3366 PetscInt pStart, pEnd; 3367 PetscInt dof, off, c; 3368 3369 PetscFunctionBegin; 3370 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3371 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3372 if (dof) PetscAssertPointer(coneOrientation, 3); 3373 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3374 if (PetscDefined(USE_DEBUG)) { 3375 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3376 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); 3377 for (c = 0; c < dof; ++c) { 3378 PetscInt cdof, o = coneOrientation[c]; 3379 3380 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3381 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); 3382 mesh->coneOrientations[off + c] = o; 3383 } 3384 } else { 3385 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3386 } 3387 PetscFunctionReturn(PETSC_SUCCESS); 3388 } 3389 3390 /*@ 3391 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3392 3393 Not Collective 3394 3395 Input Parameters: 3396 + dm - The `DMPLEX` 3397 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3398 . conePos - The local index in the cone where the point should be put 3399 - conePoint - The mesh point to insert 3400 3401 Level: beginner 3402 3403 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3404 @*/ 3405 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3406 { 3407 DM_Plex *mesh = (DM_Plex *)dm->data; 3408 PetscInt pStart, pEnd; 3409 PetscInt dof, off; 3410 3411 PetscFunctionBegin; 3412 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3413 if (PetscDefined(USE_DEBUG)) { 3414 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3415 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); 3416 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); 3417 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3418 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); 3419 } 3420 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3421 mesh->cones[off + conePos] = conePoint; 3422 PetscFunctionReturn(PETSC_SUCCESS); 3423 } 3424 3425 /*@ 3426 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3427 3428 Not Collective 3429 3430 Input Parameters: 3431 + dm - The `DMPLEX` 3432 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3433 . conePos - The local index in the cone where the point should be put 3434 - coneOrientation - The point orientation to insert 3435 3436 Level: beginner 3437 3438 Note: 3439 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3440 3441 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3442 @*/ 3443 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3444 { 3445 DM_Plex *mesh = (DM_Plex *)dm->data; 3446 PetscInt pStart, pEnd; 3447 PetscInt dof, off; 3448 3449 PetscFunctionBegin; 3450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3451 if (PetscDefined(USE_DEBUG)) { 3452 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3453 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); 3454 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3455 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); 3456 } 3457 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3458 mesh->coneOrientations[off + conePos] = coneOrientation; 3459 PetscFunctionReturn(PETSC_SUCCESS); 3460 } 3461 3462 /*@C 3463 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3464 3465 Not collective 3466 3467 Input Parameters: 3468 + dm - The DMPlex 3469 - p - The point, which must lie in the chart set with DMPlexSetChart() 3470 3471 Output Parameters: 3472 + cone - An array of points which are on the in-edges for point `p` 3473 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3474 integer giving the prescription for cone traversal. 3475 3476 Level: beginner 3477 3478 Notes: 3479 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3480 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3481 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3482 with the identity. 3483 3484 Fortran Notes: 3485 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3486 `DMPlexRestoreCone()` is not needed/available in C. 3487 3488 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3489 @*/ 3490 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3491 { 3492 DM_Plex *mesh = (DM_Plex *)dm->data; 3493 3494 PetscFunctionBegin; 3495 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3496 if (mesh->tr) { 3497 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3498 } else { 3499 PetscInt off; 3500 if (PetscDefined(USE_DEBUG)) { 3501 PetscInt dof; 3502 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3503 if (dof) { 3504 if (cone) PetscAssertPointer(cone, 3); 3505 if (ornt) PetscAssertPointer(ornt, 4); 3506 } 3507 } 3508 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3509 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3510 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3511 } 3512 PetscFunctionReturn(PETSC_SUCCESS); 3513 } 3514 3515 /*@C 3516 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3517 3518 Not Collective 3519 3520 Input Parameters: 3521 + dm - The DMPlex 3522 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3523 . cone - An array of points which are on the in-edges for point p 3524 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3525 integer giving the prescription for cone traversal. 3526 3527 Level: beginner 3528 3529 Notes: 3530 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3531 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3532 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3533 with the identity. 3534 3535 Fortran Notes: 3536 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3537 `DMPlexRestoreCone()` is not needed/available in C. 3538 3539 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3540 @*/ 3541 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3542 { 3543 DM_Plex *mesh = (DM_Plex *)dm->data; 3544 3545 PetscFunctionBegin; 3546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3547 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3548 PetscFunctionReturn(PETSC_SUCCESS); 3549 } 3550 3551 /*@ 3552 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3553 3554 Not Collective 3555 3556 Input Parameters: 3557 + dm - The `DMPLEX` 3558 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3559 3560 Output Parameter: 3561 . size - The support size for point `p` 3562 3563 Level: beginner 3564 3565 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3566 @*/ 3567 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3568 { 3569 DM_Plex *mesh = (DM_Plex *)dm->data; 3570 3571 PetscFunctionBegin; 3572 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3573 PetscAssertPointer(size, 3); 3574 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3575 PetscFunctionReturn(PETSC_SUCCESS); 3576 } 3577 3578 /*@ 3579 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3580 3581 Not Collective 3582 3583 Input Parameters: 3584 + dm - The `DMPLEX` 3585 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3586 - size - The support size for point `p` 3587 3588 Level: beginner 3589 3590 Note: 3591 This should be called after `DMPlexSetChart()`. 3592 3593 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3594 @*/ 3595 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3596 { 3597 DM_Plex *mesh = (DM_Plex *)dm->data; 3598 3599 PetscFunctionBegin; 3600 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3601 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3602 PetscFunctionReturn(PETSC_SUCCESS); 3603 } 3604 3605 /*@C 3606 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3607 3608 Not Collective 3609 3610 Input Parameters: 3611 + dm - The `DMPLEX` 3612 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3613 3614 Output Parameter: 3615 . support - An array of points which are on the out-edges for point `p` 3616 3617 Level: beginner 3618 3619 Fortran Notes: 3620 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3621 `DMPlexRestoreSupport()` is not needed/available in C. 3622 3623 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3624 @*/ 3625 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3626 { 3627 DM_Plex *mesh = (DM_Plex *)dm->data; 3628 PetscInt off; 3629 3630 PetscFunctionBegin; 3631 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3632 PetscAssertPointer(support, 3); 3633 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3634 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3635 PetscFunctionReturn(PETSC_SUCCESS); 3636 } 3637 3638 /*@ 3639 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3640 3641 Not Collective 3642 3643 Input Parameters: 3644 + dm - The `DMPLEX` 3645 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3646 - support - An array of points which are on the out-edges for point `p` 3647 3648 Level: beginner 3649 3650 Note: 3651 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3652 3653 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3654 @*/ 3655 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3656 { 3657 DM_Plex *mesh = (DM_Plex *)dm->data; 3658 PetscInt pStart, pEnd; 3659 PetscInt dof, off, c; 3660 3661 PetscFunctionBegin; 3662 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3663 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3664 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3665 if (dof) PetscAssertPointer(support, 3); 3666 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3667 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3668 for (c = 0; c < dof; ++c) { 3669 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); 3670 mesh->supports[off + c] = support[c]; 3671 } 3672 PetscFunctionReturn(PETSC_SUCCESS); 3673 } 3674 3675 /*@ 3676 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3677 3678 Not Collective 3679 3680 Input Parameters: 3681 + dm - The `DMPLEX` 3682 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3683 . supportPos - The local index in the cone where the point should be put 3684 - supportPoint - The mesh point to insert 3685 3686 Level: beginner 3687 3688 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3689 @*/ 3690 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3691 { 3692 DM_Plex *mesh = (DM_Plex *)dm->data; 3693 PetscInt pStart, pEnd; 3694 PetscInt dof, off; 3695 3696 PetscFunctionBegin; 3697 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3698 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3699 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3700 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3701 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); 3702 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); 3703 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); 3704 mesh->supports[off + supportPos] = supportPoint; 3705 PetscFunctionReturn(PETSC_SUCCESS); 3706 } 3707 3708 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3709 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3710 { 3711 switch (ct) { 3712 case DM_POLYTOPE_SEGMENT: 3713 if (o == -1) return -2; 3714 break; 3715 case DM_POLYTOPE_TRIANGLE: 3716 if (o == -3) return -1; 3717 if (o == -2) return -3; 3718 if (o == -1) return -2; 3719 break; 3720 case DM_POLYTOPE_QUADRILATERAL: 3721 if (o == -4) return -2; 3722 if (o == -3) return -1; 3723 if (o == -2) return -4; 3724 if (o == -1) return -3; 3725 break; 3726 default: 3727 return o; 3728 } 3729 return o; 3730 } 3731 3732 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3733 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3734 { 3735 switch (ct) { 3736 case DM_POLYTOPE_SEGMENT: 3737 if ((o == -2) || (o == 1)) return -1; 3738 if (o == -1) return 0; 3739 break; 3740 case DM_POLYTOPE_TRIANGLE: 3741 if (o == -3) return -2; 3742 if (o == -2) return -1; 3743 if (o == -1) return -3; 3744 break; 3745 case DM_POLYTOPE_QUADRILATERAL: 3746 if (o == -4) return -2; 3747 if (o == -3) return -1; 3748 if (o == -2) return -4; 3749 if (o == -1) return -3; 3750 break; 3751 default: 3752 return o; 3753 } 3754 return o; 3755 } 3756 3757 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3758 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3759 { 3760 PetscInt pStart, pEnd, p; 3761 3762 PetscFunctionBegin; 3763 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3764 for (p = pStart; p < pEnd; ++p) { 3765 const PetscInt *cone, *ornt; 3766 PetscInt coneSize, c; 3767 3768 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3769 PetscCall(DMPlexGetCone(dm, p, &cone)); 3770 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3771 for (c = 0; c < coneSize; ++c) { 3772 DMPolytopeType ct; 3773 const PetscInt o = ornt[c]; 3774 3775 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3776 switch (ct) { 3777 case DM_POLYTOPE_SEGMENT: 3778 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3779 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3780 break; 3781 case DM_POLYTOPE_TRIANGLE: 3782 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3783 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3784 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3785 break; 3786 case DM_POLYTOPE_QUADRILATERAL: 3787 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3788 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3789 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3790 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3791 break; 3792 default: 3793 break; 3794 } 3795 } 3796 } 3797 PetscFunctionReturn(PETSC_SUCCESS); 3798 } 3799 3800 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3801 { 3802 DM_Plex *mesh = (DM_Plex *)dm->data; 3803 3804 PetscFunctionBeginHot; 3805 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3806 if (useCone) { 3807 PetscCall(DMPlexGetConeSize(dm, p, size)); 3808 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3809 } else { 3810 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3811 PetscCall(DMPlexGetSupport(dm, p, arr)); 3812 } 3813 } else { 3814 if (useCone) { 3815 const PetscSection s = mesh->coneSection; 3816 const PetscInt ps = p - s->pStart; 3817 const PetscInt off = s->atlasOff[ps]; 3818 3819 *size = s->atlasDof[ps]; 3820 *arr = mesh->cones + off; 3821 *ornt = mesh->coneOrientations + off; 3822 } else { 3823 const PetscSection s = mesh->supportSection; 3824 const PetscInt ps = p - s->pStart; 3825 const PetscInt off = s->atlasOff[ps]; 3826 3827 *size = s->atlasDof[ps]; 3828 *arr = mesh->supports + off; 3829 } 3830 } 3831 PetscFunctionReturn(PETSC_SUCCESS); 3832 } 3833 3834 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3835 { 3836 DM_Plex *mesh = (DM_Plex *)dm->data; 3837 3838 PetscFunctionBeginHot; 3839 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3840 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3841 } 3842 PetscFunctionReturn(PETSC_SUCCESS); 3843 } 3844 3845 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3846 { 3847 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3848 PetscInt *closure; 3849 const PetscInt *tmp = NULL, *tmpO = NULL; 3850 PetscInt off = 0, tmpSize, t; 3851 3852 PetscFunctionBeginHot; 3853 if (ornt) { 3854 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3855 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; 3856 } 3857 if (*points) { 3858 closure = *points; 3859 } else { 3860 PetscInt maxConeSize, maxSupportSize; 3861 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3862 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3863 } 3864 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3865 if (ct == DM_POLYTOPE_UNKNOWN) { 3866 closure[off++] = p; 3867 closure[off++] = 0; 3868 for (t = 0; t < tmpSize; ++t) { 3869 closure[off++] = tmp[t]; 3870 closure[off++] = tmpO ? tmpO[t] : 0; 3871 } 3872 } else { 3873 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3874 3875 /* We assume that cells with a valid type have faces with a valid type */ 3876 closure[off++] = p; 3877 closure[off++] = ornt; 3878 for (t = 0; t < tmpSize; ++t) { 3879 DMPolytopeType ft; 3880 3881 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3882 closure[off++] = tmp[arr[t]]; 3883 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3884 } 3885 } 3886 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3887 if (numPoints) *numPoints = tmpSize + 1; 3888 if (points) *points = closure; 3889 PetscFunctionReturn(PETSC_SUCCESS); 3890 } 3891 3892 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3893 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3894 { 3895 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3896 const PetscInt *cone, *ornt; 3897 PetscInt *pts, *closure = NULL; 3898 DMPolytopeType ft; 3899 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3900 PetscInt dim, coneSize, c, d, clSize, cl; 3901 3902 PetscFunctionBeginHot; 3903 PetscCall(DMGetDimension(dm, &dim)); 3904 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3905 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3906 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3907 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3908 maxSize = PetscMax(coneSeries, supportSeries); 3909 if (*points) { 3910 pts = *points; 3911 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3912 c = 0; 3913 pts[c++] = point; 3914 pts[c++] = o; 3915 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3916 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3917 for (cl = 0; cl < clSize * 2; cl += 2) { 3918 pts[c++] = closure[cl]; 3919 pts[c++] = closure[cl + 1]; 3920 } 3921 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3922 for (cl = 0; cl < clSize * 2; cl += 2) { 3923 pts[c++] = closure[cl]; 3924 pts[c++] = closure[cl + 1]; 3925 } 3926 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3927 for (d = 2; d < coneSize; ++d) { 3928 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3929 pts[c++] = cone[arr[d * 2 + 0]]; 3930 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3931 } 3932 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3933 if (dim >= 3) { 3934 for (d = 2; d < coneSize; ++d) { 3935 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3936 const PetscInt *fcone, *fornt; 3937 PetscInt fconeSize, fc, i; 3938 3939 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3940 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3941 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3942 for (fc = 0; fc < fconeSize; ++fc) { 3943 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3944 const PetscInt co = farr[fc * 2 + 1]; 3945 3946 for (i = 0; i < c; i += 2) 3947 if (pts[i] == cp) break; 3948 if (i == c) { 3949 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3950 pts[c++] = cp; 3951 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3952 } 3953 } 3954 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3955 } 3956 } 3957 *numPoints = c / 2; 3958 *points = pts; 3959 PetscFunctionReturn(PETSC_SUCCESS); 3960 } 3961 3962 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3963 { 3964 DMPolytopeType ct; 3965 PetscInt *closure, *fifo; 3966 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3967 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3968 PetscInt depth, maxSize; 3969 3970 PetscFunctionBeginHot; 3971 PetscCall(DMPlexGetDepth(dm, &depth)); 3972 if (depth == 1) { 3973 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3974 PetscFunctionReturn(PETSC_SUCCESS); 3975 } 3976 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3977 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; 3978 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3979 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3980 PetscFunctionReturn(PETSC_SUCCESS); 3981 } 3982 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3983 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3984 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3985 maxSize = PetscMax(coneSeries, supportSeries); 3986 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3987 if (*points) { 3988 closure = *points; 3989 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3990 closure[closureSize++] = p; 3991 closure[closureSize++] = ornt; 3992 fifo[fifoSize++] = p; 3993 fifo[fifoSize++] = ornt; 3994 fifo[fifoSize++] = ct; 3995 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3996 while (fifoSize - fifoStart) { 3997 const PetscInt q = fifo[fifoStart++]; 3998 const PetscInt o = fifo[fifoStart++]; 3999 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4000 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4001 const PetscInt *tmp, *tmpO = NULL; 4002 PetscInt tmpSize, t; 4003 4004 if (PetscDefined(USE_DEBUG)) { 4005 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4006 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); 4007 } 4008 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4009 for (t = 0; t < tmpSize; ++t) { 4010 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4011 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4012 const PetscInt cp = tmp[ip]; 4013 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4014 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4015 PetscInt c; 4016 4017 /* Check for duplicate */ 4018 for (c = 0; c < closureSize; c += 2) { 4019 if (closure[c] == cp) break; 4020 } 4021 if (c == closureSize) { 4022 closure[closureSize++] = cp; 4023 closure[closureSize++] = co; 4024 fifo[fifoSize++] = cp; 4025 fifo[fifoSize++] = co; 4026 fifo[fifoSize++] = ct; 4027 } 4028 } 4029 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4030 } 4031 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4032 if (numPoints) *numPoints = closureSize / 2; 4033 if (points) *points = closure; 4034 PetscFunctionReturn(PETSC_SUCCESS); 4035 } 4036 4037 /*@C 4038 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4039 4040 Not Collective 4041 4042 Input Parameters: 4043 + dm - The `DMPLEX` 4044 . p - The mesh point 4045 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4046 4047 Input/Output Parameter: 4048 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4049 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4050 4051 Output Parameter: 4052 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4053 4054 Level: beginner 4055 4056 Note: 4057 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4058 4059 Fortran Notes: 4060 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4061 4062 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4063 @*/ 4064 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4065 { 4066 PetscFunctionBeginHot; 4067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4068 if (numPoints) PetscAssertPointer(numPoints, 4); 4069 if (points) PetscAssertPointer(points, 5); 4070 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4071 PetscFunctionReturn(PETSC_SUCCESS); 4072 } 4073 4074 /*@C 4075 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4076 4077 Not Collective 4078 4079 Input Parameters: 4080 + dm - The `DMPLEX` 4081 . p - The mesh point 4082 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4083 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4084 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4085 4086 Level: beginner 4087 4088 Note: 4089 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4090 4091 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4092 @*/ 4093 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4094 { 4095 PetscFunctionBeginHot; 4096 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4097 if (numPoints) *numPoints = 0; 4098 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4099 PetscFunctionReturn(PETSC_SUCCESS); 4100 } 4101 4102 /*@ 4103 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4104 4105 Not Collective 4106 4107 Input Parameter: 4108 . dm - The `DMPLEX` 4109 4110 Output Parameters: 4111 + maxConeSize - The maximum number of in-edges 4112 - maxSupportSize - The maximum number of out-edges 4113 4114 Level: beginner 4115 4116 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4117 @*/ 4118 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4119 { 4120 DM_Plex *mesh = (DM_Plex *)dm->data; 4121 4122 PetscFunctionBegin; 4123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4124 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4125 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4126 PetscFunctionReturn(PETSC_SUCCESS); 4127 } 4128 4129 PetscErrorCode DMSetUp_Plex(DM dm) 4130 { 4131 DM_Plex *mesh = (DM_Plex *)dm->data; 4132 PetscInt size, maxSupportSize; 4133 4134 PetscFunctionBegin; 4135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4136 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4137 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4138 PetscCall(PetscMalloc1(size, &mesh->cones)); 4139 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4140 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4141 if (maxSupportSize) { 4142 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4143 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4144 PetscCall(PetscMalloc1(size, &mesh->supports)); 4145 } 4146 PetscFunctionReturn(PETSC_SUCCESS); 4147 } 4148 4149 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4150 { 4151 PetscFunctionBegin; 4152 if (subdm) PetscCall(DMClone(dm, subdm)); 4153 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4154 if (subdm) (*subdm)->useNatural = dm->useNatural; 4155 if (dm->useNatural && dm->sfMigration) { 4156 PetscSF sfNatural; 4157 4158 (*subdm)->sfMigration = dm->sfMigration; 4159 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4160 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4161 (*subdm)->sfNatural = sfNatural; 4162 } 4163 PetscFunctionReturn(PETSC_SUCCESS); 4164 } 4165 4166 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4167 { 4168 PetscInt i = 0; 4169 4170 PetscFunctionBegin; 4171 PetscCall(DMClone(dms[0], superdm)); 4172 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4173 (*superdm)->useNatural = PETSC_FALSE; 4174 for (i = 0; i < len; i++) { 4175 if (dms[i]->useNatural && dms[i]->sfMigration) { 4176 PetscSF sfNatural; 4177 4178 (*superdm)->sfMigration = dms[i]->sfMigration; 4179 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4180 (*superdm)->useNatural = PETSC_TRUE; 4181 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4182 (*superdm)->sfNatural = sfNatural; 4183 break; 4184 } 4185 } 4186 PetscFunctionReturn(PETSC_SUCCESS); 4187 } 4188 4189 /*@ 4190 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4191 4192 Not Collective 4193 4194 Input Parameter: 4195 . dm - The `DMPLEX` 4196 4197 Level: beginner 4198 4199 Note: 4200 This should be called after all calls to `DMPlexSetCone()` 4201 4202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4203 @*/ 4204 PetscErrorCode DMPlexSymmetrize(DM dm) 4205 { 4206 DM_Plex *mesh = (DM_Plex *)dm->data; 4207 PetscInt *offsets; 4208 PetscInt supportSize; 4209 PetscInt pStart, pEnd, p; 4210 4211 PetscFunctionBegin; 4212 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4213 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4214 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4215 /* Calculate support sizes */ 4216 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4217 for (p = pStart; p < pEnd; ++p) { 4218 PetscInt dof, off, c; 4219 4220 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4221 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4222 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4223 } 4224 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4225 /* Calculate supports */ 4226 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4227 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4228 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4229 for (p = pStart; p < pEnd; ++p) { 4230 PetscInt dof, off, c; 4231 4232 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4233 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4234 for (c = off; c < off + dof; ++c) { 4235 const PetscInt q = mesh->cones[c]; 4236 PetscInt offS; 4237 4238 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4239 4240 mesh->supports[offS + offsets[q]] = p; 4241 ++offsets[q]; 4242 } 4243 } 4244 PetscCall(PetscFree(offsets)); 4245 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4246 PetscFunctionReturn(PETSC_SUCCESS); 4247 } 4248 4249 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4250 { 4251 IS stratumIS; 4252 4253 PetscFunctionBegin; 4254 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4255 if (PetscDefined(USE_DEBUG)) { 4256 PetscInt qStart, qEnd, numLevels, level; 4257 PetscBool overlap = PETSC_FALSE; 4258 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4259 for (level = 0; level < numLevels; level++) { 4260 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4261 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4262 overlap = PETSC_TRUE; 4263 break; 4264 } 4265 } 4266 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); 4267 } 4268 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4269 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4270 PetscCall(ISDestroy(&stratumIS)); 4271 PetscFunctionReturn(PETSC_SUCCESS); 4272 } 4273 4274 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4275 { 4276 PetscInt *pMin, *pMax; 4277 PetscInt pStart, pEnd; 4278 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4279 4280 PetscFunctionBegin; 4281 { 4282 DMLabel label2; 4283 4284 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4285 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4286 } 4287 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4288 for (PetscInt p = pStart; p < pEnd; ++p) { 4289 DMPolytopeType ct; 4290 4291 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4292 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4293 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4294 } 4295 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4296 for (PetscInt d = dmin; d <= dmax; ++d) { 4297 pMin[d] = PETSC_MAX_INT; 4298 pMax[d] = PETSC_MIN_INT; 4299 } 4300 for (PetscInt p = pStart; p < pEnd; ++p) { 4301 DMPolytopeType ct; 4302 PetscInt d; 4303 4304 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4305 d = DMPolytopeTypeGetDim(ct); 4306 pMin[d] = PetscMin(p, pMin[d]); 4307 pMax[d] = PetscMax(p, pMax[d]); 4308 } 4309 for (PetscInt d = dmin; d <= dmax; ++d) { 4310 if (pMin[d] > pMax[d]) continue; 4311 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4312 } 4313 PetscCall(PetscFree2(pMin, pMax)); 4314 PetscFunctionReturn(PETSC_SUCCESS); 4315 } 4316 4317 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4318 { 4319 PetscInt pStart, pEnd; 4320 PetscInt numRoots = 0, numLeaves = 0; 4321 4322 PetscFunctionBegin; 4323 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4324 { 4325 /* Initialize roots and count leaves */ 4326 PetscInt sMin = PETSC_MAX_INT; 4327 PetscInt sMax = PETSC_MIN_INT; 4328 PetscInt coneSize, supportSize; 4329 4330 for (PetscInt p = pStart; p < pEnd; ++p) { 4331 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4332 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4333 if (!coneSize && supportSize) { 4334 sMin = PetscMin(p, sMin); 4335 sMax = PetscMax(p, sMax); 4336 ++numRoots; 4337 } else if (!supportSize && coneSize) { 4338 ++numLeaves; 4339 } else if (!supportSize && !coneSize) { 4340 /* Isolated points */ 4341 sMin = PetscMin(p, sMin); 4342 sMax = PetscMax(p, sMax); 4343 } 4344 } 4345 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4346 } 4347 4348 if (numRoots + numLeaves == (pEnd - pStart)) { 4349 PetscInt sMin = PETSC_MAX_INT; 4350 PetscInt sMax = PETSC_MIN_INT; 4351 PetscInt coneSize, supportSize; 4352 4353 for (PetscInt p = pStart; p < pEnd; ++p) { 4354 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4355 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4356 if (!supportSize && coneSize) { 4357 sMin = PetscMin(p, sMin); 4358 sMax = PetscMax(p, sMax); 4359 } 4360 } 4361 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4362 } else { 4363 PetscInt level = 0; 4364 PetscInt qStart, qEnd; 4365 4366 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4367 while (qEnd > qStart) { 4368 PetscInt sMin = PETSC_MAX_INT; 4369 PetscInt sMax = PETSC_MIN_INT; 4370 4371 for (PetscInt q = qStart; q < qEnd; ++q) { 4372 const PetscInt *support; 4373 PetscInt supportSize; 4374 4375 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4376 PetscCall(DMPlexGetSupport(dm, q, &support)); 4377 for (PetscInt s = 0; s < supportSize; ++s) { 4378 sMin = PetscMin(support[s], sMin); 4379 sMax = PetscMax(support[s], sMax); 4380 } 4381 } 4382 PetscCall(DMLabelGetNumValues(label, &level)); 4383 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4384 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4385 } 4386 } 4387 PetscFunctionReturn(PETSC_SUCCESS); 4388 } 4389 4390 /*@ 4391 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4392 4393 Collective 4394 4395 Input Parameter: 4396 . dm - The `DMPLEX` 4397 4398 Level: beginner 4399 4400 Notes: 4401 The strata group all points of the same grade, and this function calculates the strata. This 4402 grade can be seen as the height (or depth) of the point in the DAG. 4403 4404 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4405 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4406 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4407 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4408 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4409 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4410 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4411 4412 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4413 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4414 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 4415 to interpolate only that one (e0), so that 4416 .vb 4417 cone(c0) = {e0, v2} 4418 cone(e0) = {v0, v1} 4419 .ve 4420 If `DMPlexStratify()` is run on this mesh, it will give depths 4421 .vb 4422 depth 0 = {v0, v1, v2} 4423 depth 1 = {e0, c0} 4424 .ve 4425 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4426 4427 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4428 4429 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4430 @*/ 4431 PetscErrorCode DMPlexStratify(DM dm) 4432 { 4433 DM_Plex *mesh = (DM_Plex *)dm->data; 4434 DMLabel label; 4435 PetscBool flg = PETSC_FALSE; 4436 4437 PetscFunctionBegin; 4438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4439 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4440 4441 // Create depth label 4442 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4443 PetscCall(DMCreateLabel(dm, "depth")); 4444 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4445 4446 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4447 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4448 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4449 4450 { /* just in case there is an empty process */ 4451 PetscInt numValues, maxValues = 0, v; 4452 4453 PetscCall(DMLabelGetNumValues(label, &numValues)); 4454 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4455 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4456 } 4457 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4458 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4459 PetscFunctionReturn(PETSC_SUCCESS); 4460 } 4461 4462 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4463 { 4464 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4465 PetscInt dim, depth, pheight, coneSize; 4466 4467 PetscFunctionBeginHot; 4468 PetscCall(DMGetDimension(dm, &dim)); 4469 PetscCall(DMPlexGetDepth(dm, &depth)); 4470 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4471 pheight = depth - pdepth; 4472 if (depth <= 1) { 4473 switch (pdepth) { 4474 case 0: 4475 ct = DM_POLYTOPE_POINT; 4476 break; 4477 case 1: 4478 switch (coneSize) { 4479 case 2: 4480 ct = DM_POLYTOPE_SEGMENT; 4481 break; 4482 case 3: 4483 ct = DM_POLYTOPE_TRIANGLE; 4484 break; 4485 case 4: 4486 switch (dim) { 4487 case 2: 4488 ct = DM_POLYTOPE_QUADRILATERAL; 4489 break; 4490 case 3: 4491 ct = DM_POLYTOPE_TETRAHEDRON; 4492 break; 4493 default: 4494 break; 4495 } 4496 break; 4497 case 5: 4498 ct = DM_POLYTOPE_PYRAMID; 4499 break; 4500 case 6: 4501 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4502 break; 4503 case 8: 4504 ct = DM_POLYTOPE_HEXAHEDRON; 4505 break; 4506 default: 4507 break; 4508 } 4509 } 4510 } else { 4511 if (pdepth == 0) { 4512 ct = DM_POLYTOPE_POINT; 4513 } else if (pheight == 0) { 4514 switch (dim) { 4515 case 1: 4516 switch (coneSize) { 4517 case 2: 4518 ct = DM_POLYTOPE_SEGMENT; 4519 break; 4520 default: 4521 break; 4522 } 4523 break; 4524 case 2: 4525 switch (coneSize) { 4526 case 3: 4527 ct = DM_POLYTOPE_TRIANGLE; 4528 break; 4529 case 4: 4530 ct = DM_POLYTOPE_QUADRILATERAL; 4531 break; 4532 default: 4533 break; 4534 } 4535 break; 4536 case 3: 4537 switch (coneSize) { 4538 case 4: 4539 ct = DM_POLYTOPE_TETRAHEDRON; 4540 break; 4541 case 5: { 4542 const PetscInt *cone; 4543 PetscInt faceConeSize; 4544 4545 PetscCall(DMPlexGetCone(dm, p, &cone)); 4546 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4547 switch (faceConeSize) { 4548 case 3: 4549 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4550 break; 4551 case 4: 4552 ct = DM_POLYTOPE_PYRAMID; 4553 break; 4554 } 4555 } break; 4556 case 6: 4557 ct = DM_POLYTOPE_HEXAHEDRON; 4558 break; 4559 default: 4560 break; 4561 } 4562 break; 4563 default: 4564 break; 4565 } 4566 } else if (pheight > 0) { 4567 switch (coneSize) { 4568 case 2: 4569 ct = DM_POLYTOPE_SEGMENT; 4570 break; 4571 case 3: 4572 ct = DM_POLYTOPE_TRIANGLE; 4573 break; 4574 case 4: 4575 ct = DM_POLYTOPE_QUADRILATERAL; 4576 break; 4577 default: 4578 break; 4579 } 4580 } 4581 } 4582 *pt = ct; 4583 PetscFunctionReturn(PETSC_SUCCESS); 4584 } 4585 4586 /*@ 4587 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4588 4589 Collective 4590 4591 Input Parameter: 4592 . dm - The `DMPLEX` 4593 4594 Level: developer 4595 4596 Note: 4597 This function is normally called automatically when a cell type is requested. It creates an 4598 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4599 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4600 4601 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4602 4603 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4604 @*/ 4605 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4606 { 4607 DM_Plex *mesh; 4608 DMLabel ctLabel; 4609 PetscInt pStart, pEnd, p; 4610 4611 PetscFunctionBegin; 4612 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4613 mesh = (DM_Plex *)dm->data; 4614 PetscCall(DMCreateLabel(dm, "celltype")); 4615 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4616 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4617 PetscCall(PetscFree(mesh->cellTypes)); 4618 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4619 for (p = pStart; p < pEnd; ++p) { 4620 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4621 PetscInt pdepth; 4622 4623 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4624 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4625 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4626 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4627 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4628 } 4629 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4630 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4631 PetscFunctionReturn(PETSC_SUCCESS); 4632 } 4633 4634 /*@C 4635 DMPlexGetJoin - Get an array for the join of the set of points 4636 4637 Not Collective 4638 4639 Input Parameters: 4640 + dm - The `DMPLEX` object 4641 . numPoints - The number of input points for the join 4642 - points - The input points 4643 4644 Output Parameters: 4645 + numCoveredPoints - The number of points in the join 4646 - coveredPoints - The points in the join 4647 4648 Level: intermediate 4649 4650 Note: 4651 Currently, this is restricted to a single level join 4652 4653 Fortran Notes: 4654 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4655 4656 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4657 @*/ 4658 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4659 { 4660 DM_Plex *mesh = (DM_Plex *)dm->data; 4661 PetscInt *join[2]; 4662 PetscInt joinSize, i = 0; 4663 PetscInt dof, off, p, c, m; 4664 PetscInt maxSupportSize; 4665 4666 PetscFunctionBegin; 4667 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4668 PetscAssertPointer(points, 3); 4669 PetscAssertPointer(numCoveredPoints, 4); 4670 PetscAssertPointer(coveredPoints, 5); 4671 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4672 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4673 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4674 /* Copy in support of first point */ 4675 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4676 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4677 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4678 /* Check each successive support */ 4679 for (p = 1; p < numPoints; ++p) { 4680 PetscInt newJoinSize = 0; 4681 4682 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4683 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4684 for (c = 0; c < dof; ++c) { 4685 const PetscInt point = mesh->supports[off + c]; 4686 4687 for (m = 0; m < joinSize; ++m) { 4688 if (point == join[i][m]) { 4689 join[1 - i][newJoinSize++] = point; 4690 break; 4691 } 4692 } 4693 } 4694 joinSize = newJoinSize; 4695 i = 1 - i; 4696 } 4697 *numCoveredPoints = joinSize; 4698 *coveredPoints = join[i]; 4699 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4700 PetscFunctionReturn(PETSC_SUCCESS); 4701 } 4702 4703 /*@C 4704 DMPlexRestoreJoin - Restore an array for the join of the set of points 4705 4706 Not Collective 4707 4708 Input Parameters: 4709 + dm - The `DMPLEX` object 4710 . numPoints - The number of input points for the join 4711 - points - The input points 4712 4713 Output Parameters: 4714 + numCoveredPoints - The number of points in the join 4715 - coveredPoints - The points in the join 4716 4717 Level: intermediate 4718 4719 Fortran Notes: 4720 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4721 4722 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4723 @*/ 4724 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4725 { 4726 PetscFunctionBegin; 4727 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4728 if (points) PetscAssertPointer(points, 3); 4729 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4730 PetscAssertPointer(coveredPoints, 5); 4731 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4732 if (numCoveredPoints) *numCoveredPoints = 0; 4733 PetscFunctionReturn(PETSC_SUCCESS); 4734 } 4735 4736 /*@C 4737 DMPlexGetFullJoin - Get an array for the join of the set of points 4738 4739 Not Collective 4740 4741 Input Parameters: 4742 + dm - The `DMPLEX` object 4743 . numPoints - The number of input points for the join 4744 - points - The input points 4745 4746 Output Parameters: 4747 + numCoveredPoints - The number of points in the join 4748 - coveredPoints - The points in the join 4749 4750 Level: intermediate 4751 4752 Fortran Notes: 4753 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4754 4755 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4756 @*/ 4757 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4758 { 4759 PetscInt *offsets, **closures; 4760 PetscInt *join[2]; 4761 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4762 PetscInt p, d, c, m, ms; 4763 4764 PetscFunctionBegin; 4765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4766 PetscAssertPointer(points, 3); 4767 PetscAssertPointer(numCoveredPoints, 4); 4768 PetscAssertPointer(coveredPoints, 5); 4769 4770 PetscCall(DMPlexGetDepth(dm, &depth)); 4771 PetscCall(PetscCalloc1(numPoints, &closures)); 4772 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4773 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4774 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4775 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4776 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4777 4778 for (p = 0; p < numPoints; ++p) { 4779 PetscInt closureSize; 4780 4781 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4782 4783 offsets[p * (depth + 2) + 0] = 0; 4784 for (d = 0; d < depth + 1; ++d) { 4785 PetscInt pStart, pEnd, i; 4786 4787 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4788 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4789 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4790 offsets[p * (depth + 2) + d + 1] = i; 4791 break; 4792 } 4793 } 4794 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4795 } 4796 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); 4797 } 4798 for (d = 0; d < depth + 1; ++d) { 4799 PetscInt dof; 4800 4801 /* Copy in support of first point */ 4802 dof = offsets[d + 1] - offsets[d]; 4803 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4804 /* Check each successive cone */ 4805 for (p = 1; p < numPoints && joinSize; ++p) { 4806 PetscInt newJoinSize = 0; 4807 4808 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4809 for (c = 0; c < dof; ++c) { 4810 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4811 4812 for (m = 0; m < joinSize; ++m) { 4813 if (point == join[i][m]) { 4814 join[1 - i][newJoinSize++] = point; 4815 break; 4816 } 4817 } 4818 } 4819 joinSize = newJoinSize; 4820 i = 1 - i; 4821 } 4822 if (joinSize) break; 4823 } 4824 *numCoveredPoints = joinSize; 4825 *coveredPoints = join[i]; 4826 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4827 PetscCall(PetscFree(closures)); 4828 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4829 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4830 PetscFunctionReturn(PETSC_SUCCESS); 4831 } 4832 4833 /*@C 4834 DMPlexGetMeet - Get an array for the meet of the set of points 4835 4836 Not Collective 4837 4838 Input Parameters: 4839 + dm - The `DMPLEX` object 4840 . numPoints - The number of input points for the meet 4841 - points - The input points 4842 4843 Output Parameters: 4844 + numCoveringPoints - The number of points in the meet 4845 - coveringPoints - The points in the meet 4846 4847 Level: intermediate 4848 4849 Note: 4850 Currently, this is restricted to a single level meet 4851 4852 Fortran Notes: 4853 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4854 4855 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4856 @*/ 4857 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4858 { 4859 DM_Plex *mesh = (DM_Plex *)dm->data; 4860 PetscInt *meet[2]; 4861 PetscInt meetSize, i = 0; 4862 PetscInt dof, off, p, c, m; 4863 PetscInt maxConeSize; 4864 4865 PetscFunctionBegin; 4866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4867 PetscAssertPointer(points, 3); 4868 PetscAssertPointer(numCoveringPoints, 4); 4869 PetscAssertPointer(coveringPoints, 5); 4870 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4871 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4872 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4873 /* Copy in cone of first point */ 4874 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4875 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4876 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4877 /* Check each successive cone */ 4878 for (p = 1; p < numPoints; ++p) { 4879 PetscInt newMeetSize = 0; 4880 4881 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4882 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4883 for (c = 0; c < dof; ++c) { 4884 const PetscInt point = mesh->cones[off + c]; 4885 4886 for (m = 0; m < meetSize; ++m) { 4887 if (point == meet[i][m]) { 4888 meet[1 - i][newMeetSize++] = point; 4889 break; 4890 } 4891 } 4892 } 4893 meetSize = newMeetSize; 4894 i = 1 - i; 4895 } 4896 *numCoveringPoints = meetSize; 4897 *coveringPoints = meet[i]; 4898 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4899 PetscFunctionReturn(PETSC_SUCCESS); 4900 } 4901 4902 /*@C 4903 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4904 4905 Not Collective 4906 4907 Input Parameters: 4908 + dm - The `DMPLEX` object 4909 . numPoints - The number of input points for the meet 4910 - points - The input points 4911 4912 Output Parameters: 4913 + numCoveredPoints - The number of points in the meet 4914 - coveredPoints - The points in the meet 4915 4916 Level: intermediate 4917 4918 Fortran Notes: 4919 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4920 4921 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4922 @*/ 4923 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4924 { 4925 PetscFunctionBegin; 4926 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4927 if (points) PetscAssertPointer(points, 3); 4928 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4929 PetscAssertPointer(coveredPoints, 5); 4930 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4931 if (numCoveredPoints) *numCoveredPoints = 0; 4932 PetscFunctionReturn(PETSC_SUCCESS); 4933 } 4934 4935 /*@C 4936 DMPlexGetFullMeet - Get an array for the meet of the set of points 4937 4938 Not Collective 4939 4940 Input Parameters: 4941 + dm - The `DMPLEX` object 4942 . numPoints - The number of input points for the meet 4943 - points - The input points 4944 4945 Output Parameters: 4946 + numCoveredPoints - The number of points in the meet 4947 - coveredPoints - The points in the meet 4948 4949 Level: intermediate 4950 4951 Fortran Notes: 4952 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4953 4954 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4955 @*/ 4956 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4957 { 4958 PetscInt *offsets, **closures; 4959 PetscInt *meet[2]; 4960 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4961 PetscInt p, h, c, m, mc; 4962 4963 PetscFunctionBegin; 4964 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4965 PetscAssertPointer(points, 3); 4966 PetscAssertPointer(numCoveredPoints, 4); 4967 PetscAssertPointer(coveredPoints, 5); 4968 4969 PetscCall(DMPlexGetDepth(dm, &height)); 4970 PetscCall(PetscMalloc1(numPoints, &closures)); 4971 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4972 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4973 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4974 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4975 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4976 4977 for (p = 0; p < numPoints; ++p) { 4978 PetscInt closureSize; 4979 4980 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4981 4982 offsets[p * (height + 2) + 0] = 0; 4983 for (h = 0; h < height + 1; ++h) { 4984 PetscInt pStart, pEnd, i; 4985 4986 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4987 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4988 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4989 offsets[p * (height + 2) + h + 1] = i; 4990 break; 4991 } 4992 } 4993 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4994 } 4995 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); 4996 } 4997 for (h = 0; h < height + 1; ++h) { 4998 PetscInt dof; 4999 5000 /* Copy in cone of first point */ 5001 dof = offsets[h + 1] - offsets[h]; 5002 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5003 /* Check each successive cone */ 5004 for (p = 1; p < numPoints && meetSize; ++p) { 5005 PetscInt newMeetSize = 0; 5006 5007 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5008 for (c = 0; c < dof; ++c) { 5009 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5010 5011 for (m = 0; m < meetSize; ++m) { 5012 if (point == meet[i][m]) { 5013 meet[1 - i][newMeetSize++] = point; 5014 break; 5015 } 5016 } 5017 } 5018 meetSize = newMeetSize; 5019 i = 1 - i; 5020 } 5021 if (meetSize) break; 5022 } 5023 *numCoveredPoints = meetSize; 5024 *coveredPoints = meet[i]; 5025 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5026 PetscCall(PetscFree(closures)); 5027 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5028 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5029 PetscFunctionReturn(PETSC_SUCCESS); 5030 } 5031 5032 /*@C 5033 DMPlexEqual - Determine if two `DM` have the same topology 5034 5035 Not Collective 5036 5037 Input Parameters: 5038 + dmA - A `DMPLEX` object 5039 - dmB - A `DMPLEX` object 5040 5041 Output Parameter: 5042 . equal - `PETSC_TRUE` if the topologies are identical 5043 5044 Level: intermediate 5045 5046 Note: 5047 We are not solving graph isomorphism, so we do not permute. 5048 5049 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5050 @*/ 5051 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5052 { 5053 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5054 5055 PetscFunctionBegin; 5056 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5057 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5058 PetscAssertPointer(equal, 3); 5059 5060 *equal = PETSC_FALSE; 5061 PetscCall(DMPlexGetDepth(dmA, &depth)); 5062 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5063 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5064 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5065 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5066 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5067 for (p = pStart; p < pEnd; ++p) { 5068 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5069 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5070 5071 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5072 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5073 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5074 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5075 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5076 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5077 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5078 for (c = 0; c < coneSize; ++c) { 5079 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5080 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5081 } 5082 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5083 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5084 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5085 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5086 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5087 for (s = 0; s < supportSize; ++s) { 5088 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5089 } 5090 } 5091 *equal = PETSC_TRUE; 5092 PetscFunctionReturn(PETSC_SUCCESS); 5093 } 5094 5095 /*@C 5096 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5097 5098 Not Collective 5099 5100 Input Parameters: 5101 + dm - The `DMPLEX` 5102 . cellDim - The cell dimension 5103 - numCorners - The number of vertices on a cell 5104 5105 Output Parameter: 5106 . numFaceVertices - The number of vertices on a face 5107 5108 Level: developer 5109 5110 Note: 5111 Of course this can only work for a restricted set of symmetric shapes 5112 5113 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5114 @*/ 5115 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5116 { 5117 MPI_Comm comm; 5118 5119 PetscFunctionBegin; 5120 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5121 PetscAssertPointer(numFaceVertices, 4); 5122 switch (cellDim) { 5123 case 0: 5124 *numFaceVertices = 0; 5125 break; 5126 case 1: 5127 *numFaceVertices = 1; 5128 break; 5129 case 2: 5130 switch (numCorners) { 5131 case 3: /* triangle */ 5132 *numFaceVertices = 2; /* Edge has 2 vertices */ 5133 break; 5134 case 4: /* quadrilateral */ 5135 *numFaceVertices = 2; /* Edge has 2 vertices */ 5136 break; 5137 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5138 *numFaceVertices = 3; /* Edge has 3 vertices */ 5139 break; 5140 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5141 *numFaceVertices = 3; /* Edge has 3 vertices */ 5142 break; 5143 default: 5144 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5145 } 5146 break; 5147 case 3: 5148 switch (numCorners) { 5149 case 4: /* tetradehdron */ 5150 *numFaceVertices = 3; /* Face has 3 vertices */ 5151 break; 5152 case 6: /* tet cohesive cells */ 5153 *numFaceVertices = 4; /* Face has 4 vertices */ 5154 break; 5155 case 8: /* hexahedron */ 5156 *numFaceVertices = 4; /* Face has 4 vertices */ 5157 break; 5158 case 9: /* tet cohesive Lagrange cells */ 5159 *numFaceVertices = 6; /* Face has 6 vertices */ 5160 break; 5161 case 10: /* quadratic tetrahedron */ 5162 *numFaceVertices = 6; /* Face has 6 vertices */ 5163 break; 5164 case 12: /* hex cohesive Lagrange cells */ 5165 *numFaceVertices = 6; /* Face has 6 vertices */ 5166 break; 5167 case 18: /* quadratic tet cohesive Lagrange cells */ 5168 *numFaceVertices = 6; /* Face has 6 vertices */ 5169 break; 5170 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5171 *numFaceVertices = 9; /* Face has 9 vertices */ 5172 break; 5173 default: 5174 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5175 } 5176 break; 5177 default: 5178 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5179 } 5180 PetscFunctionReturn(PETSC_SUCCESS); 5181 } 5182 5183 /*@ 5184 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5185 5186 Not Collective 5187 5188 Input Parameter: 5189 . dm - The `DMPLEX` object 5190 5191 Output Parameter: 5192 . depthLabel - The `DMLabel` recording point depth 5193 5194 Level: developer 5195 5196 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5197 @*/ 5198 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5199 { 5200 PetscFunctionBegin; 5201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5202 PetscAssertPointer(depthLabel, 2); 5203 *depthLabel = dm->depthLabel; 5204 PetscFunctionReturn(PETSC_SUCCESS); 5205 } 5206 5207 /*@ 5208 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5209 5210 Not Collective 5211 5212 Input Parameter: 5213 . dm - The `DMPLEX` object 5214 5215 Output Parameter: 5216 . depth - The number of strata (breadth first levels) in the DAG 5217 5218 Level: developer 5219 5220 Notes: 5221 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5222 5223 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5224 5225 An empty mesh gives -1. 5226 5227 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5228 @*/ 5229 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5230 { 5231 DM_Plex *mesh = (DM_Plex *)dm->data; 5232 DMLabel label; 5233 PetscInt d = 0; 5234 5235 PetscFunctionBegin; 5236 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5237 PetscAssertPointer(depth, 2); 5238 if (mesh->tr) { 5239 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5240 } else { 5241 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5242 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5243 *depth = d - 1; 5244 } 5245 PetscFunctionReturn(PETSC_SUCCESS); 5246 } 5247 5248 /*@ 5249 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5250 5251 Not Collective 5252 5253 Input Parameters: 5254 + dm - The `DMPLEX` object 5255 - depth - The requested depth 5256 5257 Output Parameters: 5258 + start - The first point at this `depth` 5259 - end - One beyond the last point at this `depth` 5260 5261 Level: developer 5262 5263 Notes: 5264 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5265 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5266 higher dimension, e.g., "edges". 5267 5268 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5269 @*/ 5270 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5271 { 5272 DM_Plex *mesh = (DM_Plex *)dm->data; 5273 DMLabel label; 5274 PetscInt pStart, pEnd; 5275 5276 PetscFunctionBegin; 5277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5278 if (start) { 5279 PetscAssertPointer(start, 3); 5280 *start = 0; 5281 } 5282 if (end) { 5283 PetscAssertPointer(end, 4); 5284 *end = 0; 5285 } 5286 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5287 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5288 if (depth < 0) { 5289 if (start) *start = pStart; 5290 if (end) *end = pEnd; 5291 PetscFunctionReturn(PETSC_SUCCESS); 5292 } 5293 if (mesh->tr) { 5294 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5295 } else { 5296 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5297 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5298 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5299 } 5300 PetscFunctionReturn(PETSC_SUCCESS); 5301 } 5302 5303 /*@ 5304 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5305 5306 Not Collective 5307 5308 Input Parameters: 5309 + dm - The `DMPLEX` object 5310 - height - The requested height 5311 5312 Output Parameters: 5313 + start - The first point at this `height` 5314 - end - One beyond the last point at this `height` 5315 5316 Level: developer 5317 5318 Notes: 5319 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5320 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5321 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5322 5323 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5324 @*/ 5325 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5326 { 5327 DMLabel label; 5328 PetscInt depth, pStart, pEnd; 5329 5330 PetscFunctionBegin; 5331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5332 if (start) { 5333 PetscAssertPointer(start, 3); 5334 *start = 0; 5335 } 5336 if (end) { 5337 PetscAssertPointer(end, 4); 5338 *end = 0; 5339 } 5340 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5341 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5342 if (height < 0) { 5343 if (start) *start = pStart; 5344 if (end) *end = pEnd; 5345 PetscFunctionReturn(PETSC_SUCCESS); 5346 } 5347 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5348 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5349 else PetscCall(DMGetDimension(dm, &depth)); 5350 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5351 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5352 PetscFunctionReturn(PETSC_SUCCESS); 5353 } 5354 5355 /*@ 5356 DMPlexGetPointDepth - Get the `depth` of a given point 5357 5358 Not Collective 5359 5360 Input Parameters: 5361 + dm - The `DMPLEX` object 5362 - point - The point 5363 5364 Output Parameter: 5365 . depth - The depth of the `point` 5366 5367 Level: intermediate 5368 5369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5370 @*/ 5371 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5372 { 5373 PetscFunctionBegin; 5374 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5375 PetscAssertPointer(depth, 3); 5376 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5377 PetscFunctionReturn(PETSC_SUCCESS); 5378 } 5379 5380 /*@ 5381 DMPlexGetPointHeight - Get the `height` of a given point 5382 5383 Not Collective 5384 5385 Input Parameters: 5386 + dm - The `DMPLEX` object 5387 - point - The point 5388 5389 Output Parameter: 5390 . height - The height of the `point` 5391 5392 Level: intermediate 5393 5394 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5395 @*/ 5396 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5397 { 5398 PetscInt n, pDepth; 5399 5400 PetscFunctionBegin; 5401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5402 PetscAssertPointer(height, 3); 5403 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5404 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5405 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5406 PetscFunctionReturn(PETSC_SUCCESS); 5407 } 5408 5409 /*@ 5410 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5411 5412 Not Collective 5413 5414 Input Parameter: 5415 . dm - The `DMPLEX` object 5416 5417 Output Parameter: 5418 . celltypeLabel - The `DMLabel` recording cell polytope type 5419 5420 Level: developer 5421 5422 Note: 5423 This function will trigger automatica computation of cell types. This can be disabled by calling 5424 `DMCreateLabel`(dm, "celltype") beforehand. 5425 5426 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5427 @*/ 5428 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5429 { 5430 PetscFunctionBegin; 5431 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5432 PetscAssertPointer(celltypeLabel, 2); 5433 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5434 *celltypeLabel = dm->celltypeLabel; 5435 PetscFunctionReturn(PETSC_SUCCESS); 5436 } 5437 5438 /*@ 5439 DMPlexGetCellType - Get the polytope type of a given cell 5440 5441 Not Collective 5442 5443 Input Parameters: 5444 + dm - The `DMPLEX` object 5445 - cell - The cell 5446 5447 Output Parameter: 5448 . celltype - The polytope type of the cell 5449 5450 Level: intermediate 5451 5452 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5453 @*/ 5454 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5455 { 5456 DM_Plex *mesh = (DM_Plex *)dm->data; 5457 DMLabel label; 5458 PetscInt ct; 5459 5460 PetscFunctionBegin; 5461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5462 PetscAssertPointer(celltype, 3); 5463 if (mesh->tr) { 5464 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5465 } else { 5466 PetscInt pStart, pEnd; 5467 5468 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5469 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5470 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5471 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5472 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5473 for (PetscInt p = pStart; p < pEnd; p++) { 5474 PetscCall(DMLabelGetValue(label, p, &ct)); 5475 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5476 } 5477 } 5478 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5479 if (PetscDefined(USE_DEBUG)) { 5480 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5481 PetscCall(DMLabelGetValue(label, cell, &ct)); 5482 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5483 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5484 } 5485 } 5486 PetscFunctionReturn(PETSC_SUCCESS); 5487 } 5488 5489 /*@ 5490 DMPlexSetCellType - Set the polytope type of a given cell 5491 5492 Not Collective 5493 5494 Input Parameters: 5495 + dm - The `DMPLEX` object 5496 . cell - The cell 5497 - celltype - The polytope type of the cell 5498 5499 Level: advanced 5500 5501 Note: 5502 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5503 is executed. This function will override the computed type. However, if automatic classification will not succeed 5504 and a user wants to manually specify all types, the classification must be disabled by calling 5505 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5506 5507 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5508 @*/ 5509 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5510 { 5511 DM_Plex *mesh = (DM_Plex *)dm->data; 5512 DMLabel label; 5513 PetscInt pStart, pEnd; 5514 5515 PetscFunctionBegin; 5516 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5517 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5518 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5519 PetscCall(DMLabelSetValue(label, cell, celltype)); 5520 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5521 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5522 PetscFunctionReturn(PETSC_SUCCESS); 5523 } 5524 5525 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5526 { 5527 PetscSection section, s; 5528 Mat m; 5529 PetscInt maxHeight; 5530 const char *prefix; 5531 5532 PetscFunctionBegin; 5533 PetscCall(DMClone(dm, cdm)); 5534 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5535 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5536 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5537 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5538 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5539 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5540 PetscCall(DMSetLocalSection(*cdm, section)); 5541 PetscCall(PetscSectionDestroy(§ion)); 5542 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5543 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5544 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5545 PetscCall(PetscSectionDestroy(&s)); 5546 PetscCall(MatDestroy(&m)); 5547 5548 PetscCall(DMSetNumFields(*cdm, 1)); 5549 PetscCall(DMCreateDS(*cdm)); 5550 (*cdm)->cloneOpts = PETSC_TRUE; 5551 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5552 PetscFunctionReturn(PETSC_SUCCESS); 5553 } 5554 5555 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5556 { 5557 Vec coordsLocal, cellCoordsLocal; 5558 DM coordsDM, cellCoordsDM; 5559 5560 PetscFunctionBegin; 5561 *field = NULL; 5562 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5563 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5564 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5565 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5566 if (coordsLocal && coordsDM) { 5567 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5568 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5569 } 5570 PetscFunctionReturn(PETSC_SUCCESS); 5571 } 5572 5573 /*@C 5574 DMPlexGetConeSection - Return a section which describes the layout of cone data 5575 5576 Not Collective 5577 5578 Input Parameter: 5579 . dm - The `DMPLEX` object 5580 5581 Output Parameter: 5582 . section - The `PetscSection` object 5583 5584 Level: developer 5585 5586 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5587 @*/ 5588 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5589 { 5590 DM_Plex *mesh = (DM_Plex *)dm->data; 5591 5592 PetscFunctionBegin; 5593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5594 if (section) *section = mesh->coneSection; 5595 PetscFunctionReturn(PETSC_SUCCESS); 5596 } 5597 5598 /*@C 5599 DMPlexGetSupportSection - Return a section which describes the layout of support data 5600 5601 Not Collective 5602 5603 Input Parameter: 5604 . dm - The `DMPLEX` object 5605 5606 Output Parameter: 5607 . section - The `PetscSection` object 5608 5609 Level: developer 5610 5611 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5612 @*/ 5613 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5614 { 5615 DM_Plex *mesh = (DM_Plex *)dm->data; 5616 5617 PetscFunctionBegin; 5618 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5619 if (section) *section = mesh->supportSection; 5620 PetscFunctionReturn(PETSC_SUCCESS); 5621 } 5622 5623 /*@C 5624 DMPlexGetCones - Return cone data 5625 5626 Not Collective 5627 5628 Input Parameter: 5629 . dm - The `DMPLEX` object 5630 5631 Output Parameter: 5632 . cones - The cone for each point 5633 5634 Level: developer 5635 5636 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5637 @*/ 5638 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5639 { 5640 DM_Plex *mesh = (DM_Plex *)dm->data; 5641 5642 PetscFunctionBegin; 5643 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5644 if (cones) *cones = mesh->cones; 5645 PetscFunctionReturn(PETSC_SUCCESS); 5646 } 5647 5648 /*@C 5649 DMPlexGetConeOrientations - Return cone orientation data 5650 5651 Not Collective 5652 5653 Input Parameter: 5654 . dm - The `DMPLEX` object 5655 5656 Output Parameter: 5657 . coneOrientations - The array of cone orientations for all points 5658 5659 Level: developer 5660 5661 Notes: 5662 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5663 5664 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5665 5666 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5667 @*/ 5668 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5669 { 5670 DM_Plex *mesh = (DM_Plex *)dm->data; 5671 5672 PetscFunctionBegin; 5673 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5674 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5675 PetscFunctionReturn(PETSC_SUCCESS); 5676 } 5677 5678 /******************************** FEM Support **********************************/ 5679 5680 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5681 { 5682 PetscInt depth; 5683 5684 PetscFunctionBegin; 5685 PetscCall(DMPlexGetDepth(plex, &depth)); 5686 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5687 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5688 PetscFunctionReturn(PETSC_SUCCESS); 5689 } 5690 5691 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5692 { 5693 PetscInt depth; 5694 5695 PetscFunctionBegin; 5696 PetscCall(DMPlexGetDepth(plex, &depth)); 5697 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5698 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5699 PetscFunctionReturn(PETSC_SUCCESS); 5700 } 5701 5702 /* 5703 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5704 representing a line in the section. 5705 */ 5706 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5707 { 5708 PetscObject obj; 5709 PetscClassId id; 5710 PetscFE fe = NULL; 5711 5712 PetscFunctionBeginHot; 5713 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5714 PetscCall(DMGetField(dm, field, NULL, &obj)); 5715 PetscCall(PetscObjectGetClassId(obj, &id)); 5716 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5717 5718 if (!fe) { 5719 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5720 /* An order k SEM disc has k-1 dofs on an edge */ 5721 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5722 *k = *k / *Nc + 1; 5723 } else { 5724 PetscInt dual_space_size, dim; 5725 PetscDualSpace dsp; 5726 5727 PetscCall(DMGetDimension(dm, &dim)); 5728 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5729 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5730 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5731 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5732 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5733 } 5734 PetscFunctionReturn(PETSC_SUCCESS); 5735 } 5736 5737 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5738 { 5739 PetscFunctionBeginHot; 5740 if (tensor) { 5741 *dof = PetscPowInt(k + 1, dim); 5742 } else { 5743 switch (dim) { 5744 case 1: 5745 *dof = k + 1; 5746 break; 5747 case 2: 5748 *dof = ((k + 1) * (k + 2)) / 2; 5749 break; 5750 case 3: 5751 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5752 break; 5753 default: 5754 *dof = 0; 5755 } 5756 } 5757 PetscFunctionReturn(PETSC_SUCCESS); 5758 } 5759 5760 /*@ 5761 5762 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5763 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5764 section provided (or the section of the `DM`). 5765 5766 Input Parameters: 5767 + dm - The `DM` 5768 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5769 - section - The `PetscSection` to reorder, or `NULL` for the default section 5770 5771 Example: 5772 A typical interpolated single-quad mesh might order points as 5773 .vb 5774 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5775 5776 v4 -- e6 -- v3 5777 | | 5778 e7 c0 e8 5779 | | 5780 v1 -- e5 -- v2 5781 .ve 5782 5783 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5784 dofs in the order of points, e.g., 5785 .vb 5786 c0 -> [0,1,2,3] 5787 v1 -> [4] 5788 ... 5789 e5 -> [8, 9] 5790 .ve 5791 5792 which corresponds to the dofs 5793 .vb 5794 6 10 11 7 5795 13 2 3 15 5796 12 0 1 14 5797 4 8 9 5 5798 .ve 5799 5800 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5801 .vb 5802 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5803 .ve 5804 5805 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5806 .vb 5807 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5808 .ve 5809 5810 Level: developer 5811 5812 Notes: 5813 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5814 degree of the basis. 5815 5816 This is required to run with libCEED. 5817 5818 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5819 @*/ 5820 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5821 { 5822 DMLabel label; 5823 PetscInt dim, depth = -1, eStart = -1, Nf; 5824 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5825 5826 PetscFunctionBegin; 5827 PetscCall(DMGetDimension(dm, &dim)); 5828 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5829 if (point < 0) { 5830 PetscInt sStart, sEnd; 5831 5832 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5833 point = sEnd - sStart ? sStart : point; 5834 } 5835 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5836 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5837 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5838 if (depth == 1) { 5839 eStart = point; 5840 } else if (depth == dim) { 5841 const PetscInt *cone; 5842 5843 PetscCall(DMPlexGetCone(dm, point, &cone)); 5844 if (dim == 2) eStart = cone[0]; 5845 else if (dim == 3) { 5846 const PetscInt *cone2; 5847 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5848 eStart = cone2[0]; 5849 } 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); 5850 } 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); 5851 5852 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5853 for (PetscInt d = 1; d <= dim; d++) { 5854 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5855 PetscInt *perm; 5856 5857 for (f = 0; f < Nf; ++f) { 5858 PetscInt dof; 5859 5860 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5861 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5862 if (!continuous && d < dim) continue; 5863 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5864 size += dof * Nc; 5865 } 5866 PetscCall(PetscMalloc1(size, &perm)); 5867 for (f = 0; f < Nf; ++f) { 5868 switch (d) { 5869 case 1: 5870 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5871 if (!continuous && d < dim) continue; 5872 /* 5873 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5874 We want [ vtx0; edge of length k-1; vtx1 ] 5875 */ 5876 if (continuous) { 5877 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5878 for (i = 0; i < k - 1; i++) 5879 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5880 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5881 foffset = offset; 5882 } else { 5883 PetscInt dof; 5884 5885 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5886 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5887 foffset = offset; 5888 } 5889 break; 5890 case 2: 5891 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5892 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5893 if (!continuous && d < dim) continue; 5894 /* The SEM order is 5895 5896 v_lb, {e_b}, v_rb, 5897 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5898 v_lt, reverse {e_t}, v_rt 5899 */ 5900 if (continuous) { 5901 const PetscInt of = 0; 5902 const PetscInt oeb = of + PetscSqr(k - 1); 5903 const PetscInt oer = oeb + (k - 1); 5904 const PetscInt oet = oer + (k - 1); 5905 const PetscInt oel = oet + (k - 1); 5906 const PetscInt ovlb = oel + (k - 1); 5907 const PetscInt ovrb = ovlb + 1; 5908 const PetscInt ovrt = ovrb + 1; 5909 const PetscInt ovlt = ovrt + 1; 5910 PetscInt o; 5911 5912 /* bottom */ 5913 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5914 for (o = oeb; o < oer; ++o) 5915 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5916 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5917 /* middle */ 5918 for (i = 0; i < k - 1; ++i) { 5919 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5920 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5921 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5922 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5923 } 5924 /* top */ 5925 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5926 for (o = oel - 1; o >= oet; --o) 5927 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5928 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5929 foffset = offset; 5930 } else { 5931 PetscInt dof; 5932 5933 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5934 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5935 foffset = offset; 5936 } 5937 break; 5938 case 3: 5939 /* The original hex closure is 5940 5941 {c, 5942 f_b, f_t, f_f, f_b, f_r, f_l, 5943 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5944 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5945 */ 5946 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5947 if (!continuous && d < dim) continue; 5948 /* The SEM order is 5949 Bottom Slice 5950 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5951 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5952 v_blb, {e_bb}, v_brb, 5953 5954 Middle Slice (j) 5955 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5956 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5957 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5958 5959 Top Slice 5960 v_tlf, {e_tf}, v_trf, 5961 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5962 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5963 */ 5964 if (continuous) { 5965 const PetscInt oc = 0; 5966 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5967 const PetscInt oft = ofb + PetscSqr(k - 1); 5968 const PetscInt off = oft + PetscSqr(k - 1); 5969 const PetscInt ofk = off + PetscSqr(k - 1); 5970 const PetscInt ofr = ofk + PetscSqr(k - 1); 5971 const PetscInt ofl = ofr + PetscSqr(k - 1); 5972 const PetscInt oebl = ofl + PetscSqr(k - 1); 5973 const PetscInt oebb = oebl + (k - 1); 5974 const PetscInt oebr = oebb + (k - 1); 5975 const PetscInt oebf = oebr + (k - 1); 5976 const PetscInt oetf = oebf + (k - 1); 5977 const PetscInt oetr = oetf + (k - 1); 5978 const PetscInt oetb = oetr + (k - 1); 5979 const PetscInt oetl = oetb + (k - 1); 5980 const PetscInt oerf = oetl + (k - 1); 5981 const PetscInt oelf = oerf + (k - 1); 5982 const PetscInt oelb = oelf + (k - 1); 5983 const PetscInt oerb = oelb + (k - 1); 5984 const PetscInt ovblf = oerb + (k - 1); 5985 const PetscInt ovblb = ovblf + 1; 5986 const PetscInt ovbrb = ovblb + 1; 5987 const PetscInt ovbrf = ovbrb + 1; 5988 const PetscInt ovtlf = ovbrf + 1; 5989 const PetscInt ovtrf = ovtlf + 1; 5990 const PetscInt ovtrb = ovtrf + 1; 5991 const PetscInt ovtlb = ovtrb + 1; 5992 PetscInt o, n; 5993 5994 /* Bottom Slice */ 5995 /* bottom */ 5996 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5997 for (o = oetf - 1; o >= oebf; --o) 5998 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5999 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6000 /* middle */ 6001 for (i = 0; i < k - 1; ++i) { 6002 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6003 for (n = 0; n < k - 1; ++n) { 6004 o = ofb + n * (k - 1) + i; 6005 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6006 } 6007 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6008 } 6009 /* top */ 6010 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6011 for (o = oebb; o < oebr; ++o) 6012 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6013 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6014 6015 /* Middle Slice */ 6016 for (j = 0; j < k - 1; ++j) { 6017 /* bottom */ 6018 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6019 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6020 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6021 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6022 /* middle */ 6023 for (i = 0; i < k - 1; ++i) { 6024 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6025 for (n = 0; n < k - 1; ++n) 6026 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6027 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6028 } 6029 /* top */ 6030 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6031 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6032 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6033 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6034 } 6035 6036 /* Top Slice */ 6037 /* bottom */ 6038 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6039 for (o = oetf; o < oetr; ++o) 6040 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6041 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6042 /* middle */ 6043 for (i = 0; i < k - 1; ++i) { 6044 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6045 for (n = 0; n < k - 1; ++n) 6046 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6047 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6048 } 6049 /* top */ 6050 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6051 for (o = oetl - 1; o >= oetb; --o) 6052 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6053 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6054 6055 foffset = offset; 6056 } else { 6057 PetscInt dof; 6058 6059 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6060 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6061 foffset = offset; 6062 } 6063 break; 6064 default: 6065 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6066 } 6067 } 6068 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6069 /* Check permutation */ 6070 { 6071 PetscInt *check; 6072 6073 PetscCall(PetscMalloc1(size, &check)); 6074 for (i = 0; i < size; ++i) { 6075 check[i] = -1; 6076 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6077 } 6078 for (i = 0; i < size; ++i) check[perm[i]] = i; 6079 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6080 PetscCall(PetscFree(check)); 6081 } 6082 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6083 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6084 PetscInt *loc_perm; 6085 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6086 for (PetscInt i = 0; i < size; i++) { 6087 loc_perm[i] = perm[i]; 6088 loc_perm[size + i] = size + perm[i]; 6089 } 6090 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6091 } 6092 } 6093 PetscFunctionReturn(PETSC_SUCCESS); 6094 } 6095 6096 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6097 { 6098 PetscDS prob; 6099 PetscInt depth, Nf, h; 6100 DMLabel label; 6101 6102 PetscFunctionBeginHot; 6103 PetscCall(DMGetDS(dm, &prob)); 6104 Nf = prob->Nf; 6105 label = dm->depthLabel; 6106 *dspace = NULL; 6107 if (field < Nf) { 6108 PetscObject disc = prob->disc[field]; 6109 6110 if (disc->classid == PETSCFE_CLASSID) { 6111 PetscDualSpace dsp; 6112 6113 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6114 PetscCall(DMLabelGetNumValues(label, &depth)); 6115 PetscCall(DMLabelGetValue(label, point, &h)); 6116 h = depth - 1 - h; 6117 if (h) { 6118 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6119 } else { 6120 *dspace = dsp; 6121 } 6122 } 6123 } 6124 PetscFunctionReturn(PETSC_SUCCESS); 6125 } 6126 6127 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6128 { 6129 PetscScalar *array; 6130 const PetscScalar *vArray; 6131 const PetscInt *cone, *coneO; 6132 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6133 6134 PetscFunctionBeginHot; 6135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6136 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6137 PetscCall(DMPlexGetCone(dm, point, &cone)); 6138 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6139 if (!values || !*values) { 6140 if ((point >= pStart) && (point < pEnd)) { 6141 PetscInt dof; 6142 6143 PetscCall(PetscSectionGetDof(section, point, &dof)); 6144 size += dof; 6145 } 6146 for (p = 0; p < numPoints; ++p) { 6147 const PetscInt cp = cone[p]; 6148 PetscInt dof; 6149 6150 if ((cp < pStart) || (cp >= pEnd)) continue; 6151 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6152 size += dof; 6153 } 6154 if (!values) { 6155 if (csize) *csize = size; 6156 PetscFunctionReturn(PETSC_SUCCESS); 6157 } 6158 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6159 } else { 6160 array = *values; 6161 } 6162 size = 0; 6163 PetscCall(VecGetArrayRead(v, &vArray)); 6164 if ((point >= pStart) && (point < pEnd)) { 6165 PetscInt dof, off, d; 6166 const PetscScalar *varr; 6167 6168 PetscCall(PetscSectionGetDof(section, point, &dof)); 6169 PetscCall(PetscSectionGetOffset(section, point, &off)); 6170 varr = PetscSafePointerPlusOffset(vArray, off); 6171 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6172 size += dof; 6173 } 6174 for (p = 0; p < numPoints; ++p) { 6175 const PetscInt cp = cone[p]; 6176 PetscInt o = coneO[p]; 6177 PetscInt dof, off, d; 6178 const PetscScalar *varr; 6179 6180 if ((cp < pStart) || (cp >= pEnd)) continue; 6181 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6182 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6183 varr = PetscSafePointerPlusOffset(vArray, off); 6184 if (o >= 0) { 6185 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6186 } else { 6187 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6188 } 6189 size += dof; 6190 } 6191 PetscCall(VecRestoreArrayRead(v, &vArray)); 6192 if (!*values) { 6193 if (csize) *csize = size; 6194 *values = array; 6195 } else { 6196 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6197 *csize = size; 6198 } 6199 PetscFunctionReturn(PETSC_SUCCESS); 6200 } 6201 6202 /* Compress out points not in the section */ 6203 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6204 { 6205 const PetscInt np = *numPoints; 6206 PetscInt pStart, pEnd, p, q; 6207 6208 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6209 for (p = 0, q = 0; p < np; ++p) { 6210 const PetscInt r = points[p * 2]; 6211 if ((r >= pStart) && (r < pEnd)) { 6212 points[q * 2] = r; 6213 points[q * 2 + 1] = points[p * 2 + 1]; 6214 ++q; 6215 } 6216 } 6217 *numPoints = q; 6218 return PETSC_SUCCESS; 6219 } 6220 6221 /* Compressed closure does not apply closure permutation */ 6222 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6223 { 6224 const PetscInt *cla = NULL; 6225 PetscInt np, *pts = NULL; 6226 6227 PetscFunctionBeginHot; 6228 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6229 if (!ornt && *clPoints) { 6230 PetscInt dof, off; 6231 6232 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6233 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6234 PetscCall(ISGetIndices(*clPoints, &cla)); 6235 np = dof / 2; 6236 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6237 } else { 6238 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6239 PetscCall(CompressPoints_Private(section, &np, pts)); 6240 } 6241 *numPoints = np; 6242 *points = pts; 6243 *clp = cla; 6244 PetscFunctionReturn(PETSC_SUCCESS); 6245 } 6246 6247 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6248 { 6249 PetscFunctionBeginHot; 6250 if (!*clPoints) { 6251 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6252 } else { 6253 PetscCall(ISRestoreIndices(*clPoints, clp)); 6254 } 6255 *numPoints = 0; 6256 *points = NULL; 6257 *clSec = NULL; 6258 *clPoints = NULL; 6259 *clp = NULL; 6260 PetscFunctionReturn(PETSC_SUCCESS); 6261 } 6262 6263 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6264 { 6265 PetscInt offset = 0, p; 6266 const PetscInt **perms = NULL; 6267 const PetscScalar **flips = NULL; 6268 6269 PetscFunctionBeginHot; 6270 *size = 0; 6271 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6272 for (p = 0; p < numPoints; p++) { 6273 const PetscInt point = points[2 * p]; 6274 const PetscInt *perm = perms ? perms[p] : NULL; 6275 const PetscScalar *flip = flips ? flips[p] : NULL; 6276 PetscInt dof, off, d; 6277 const PetscScalar *varr; 6278 6279 PetscCall(PetscSectionGetDof(section, point, &dof)); 6280 PetscCall(PetscSectionGetOffset(section, point, &off)); 6281 varr = PetscSafePointerPlusOffset(vArray, off); 6282 if (clperm) { 6283 if (perm) { 6284 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6285 } else { 6286 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6287 } 6288 if (flip) { 6289 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6290 } 6291 } else { 6292 if (perm) { 6293 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6294 } else { 6295 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6296 } 6297 if (flip) { 6298 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6299 } 6300 } 6301 offset += dof; 6302 } 6303 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6304 *size = offset; 6305 PetscFunctionReturn(PETSC_SUCCESS); 6306 } 6307 6308 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[]) 6309 { 6310 PetscInt offset = 0, f; 6311 6312 PetscFunctionBeginHot; 6313 *size = 0; 6314 for (f = 0; f < numFields; ++f) { 6315 PetscInt p; 6316 const PetscInt **perms = NULL; 6317 const PetscScalar **flips = NULL; 6318 6319 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6320 for (p = 0; p < numPoints; p++) { 6321 const PetscInt point = points[2 * p]; 6322 PetscInt fdof, foff, b; 6323 const PetscScalar *varr; 6324 const PetscInt *perm = perms ? perms[p] : NULL; 6325 const PetscScalar *flip = flips ? flips[p] : NULL; 6326 6327 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6328 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6329 varr = &vArray[foff]; 6330 if (clperm) { 6331 if (perm) { 6332 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6333 } else { 6334 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6335 } 6336 if (flip) { 6337 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6338 } 6339 } else { 6340 if (perm) { 6341 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6342 } else { 6343 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6344 } 6345 if (flip) { 6346 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6347 } 6348 } 6349 offset += fdof; 6350 } 6351 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6352 } 6353 *size = offset; 6354 PetscFunctionReturn(PETSC_SUCCESS); 6355 } 6356 6357 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6358 { 6359 PetscSection clSection; 6360 IS clPoints; 6361 PetscInt *points = NULL; 6362 const PetscInt *clp, *perm = NULL; 6363 PetscInt depth, numFields, numPoints, asize; 6364 6365 PetscFunctionBeginHot; 6366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6367 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6368 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6369 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6370 PetscCall(DMPlexGetDepth(dm, &depth)); 6371 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6372 if (depth == 1 && numFields < 2) { 6373 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6374 PetscFunctionReturn(PETSC_SUCCESS); 6375 } 6376 /* Get points */ 6377 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6378 /* Get sizes */ 6379 asize = 0; 6380 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6381 PetscInt dof; 6382 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6383 asize += dof; 6384 } 6385 if (values) { 6386 const PetscScalar *vArray; 6387 PetscInt size; 6388 6389 if (*values) { 6390 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); 6391 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6392 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6393 PetscCall(VecGetArrayRead(v, &vArray)); 6394 /* Get values */ 6395 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6396 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6397 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6398 /* Cleanup array */ 6399 PetscCall(VecRestoreArrayRead(v, &vArray)); 6400 } 6401 if (csize) *csize = asize; 6402 /* Cleanup points */ 6403 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6404 PetscFunctionReturn(PETSC_SUCCESS); 6405 } 6406 6407 /*@C 6408 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6409 6410 Not collective 6411 6412 Input Parameters: 6413 + dm - The `DM` 6414 . section - The section describing the layout in `v`, or `NULL` to use the default section 6415 . v - The local vector 6416 - point - The point in the `DM` 6417 6418 Input/Output Parameters: 6419 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6420 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6421 if the user provided `NULL`, it is a borrowed array and should not be freed 6422 6423 Level: intermediate 6424 6425 Notes: 6426 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6427 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6428 assembly function, and a user may already have allocated storage for this operation. 6429 6430 A typical use could be 6431 .vb 6432 values = NULL; 6433 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6434 for (cl = 0; cl < clSize; ++cl) { 6435 <Compute on closure> 6436 } 6437 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6438 .ve 6439 or 6440 .vb 6441 PetscMalloc1(clMaxSize, &values); 6442 for (p = pStart; p < pEnd; ++p) { 6443 clSize = clMaxSize; 6444 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6445 for (cl = 0; cl < clSize; ++cl) { 6446 <Compute on closure> 6447 } 6448 } 6449 PetscFree(values); 6450 .ve 6451 6452 Fortran Notes: 6453 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6454 6455 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6456 @*/ 6457 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6458 { 6459 PetscFunctionBeginHot; 6460 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6461 PetscFunctionReturn(PETSC_SUCCESS); 6462 } 6463 6464 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6465 { 6466 DMLabel depthLabel; 6467 PetscSection clSection; 6468 IS clPoints; 6469 PetscScalar *array; 6470 const PetscScalar *vArray; 6471 PetscInt *points = NULL; 6472 const PetscInt *clp, *perm = NULL; 6473 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6474 6475 PetscFunctionBeginHot; 6476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6477 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6478 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6479 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6480 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6481 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6482 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6483 if (mdepth == 1 && numFields < 2) { 6484 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6485 PetscFunctionReturn(PETSC_SUCCESS); 6486 } 6487 /* Get points */ 6488 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6489 for (clsize = 0, p = 0; p < Np; p++) { 6490 PetscInt dof; 6491 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6492 clsize += dof; 6493 } 6494 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6495 /* Filter points */ 6496 for (p = 0; p < numPoints * 2; p += 2) { 6497 PetscInt dep; 6498 6499 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6500 if (dep != depth) continue; 6501 points[Np * 2 + 0] = points[p]; 6502 points[Np * 2 + 1] = points[p + 1]; 6503 ++Np; 6504 } 6505 /* Get array */ 6506 if (!values || !*values) { 6507 PetscInt asize = 0, dof; 6508 6509 for (p = 0; p < Np * 2; p += 2) { 6510 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6511 asize += dof; 6512 } 6513 if (!values) { 6514 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6515 if (csize) *csize = asize; 6516 PetscFunctionReturn(PETSC_SUCCESS); 6517 } 6518 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6519 } else { 6520 array = *values; 6521 } 6522 PetscCall(VecGetArrayRead(v, &vArray)); 6523 /* Get values */ 6524 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6525 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6526 /* Cleanup points */ 6527 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6528 /* Cleanup array */ 6529 PetscCall(VecRestoreArrayRead(v, &vArray)); 6530 if (!*values) { 6531 if (csize) *csize = size; 6532 *values = array; 6533 } else { 6534 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6535 *csize = size; 6536 } 6537 PetscFunctionReturn(PETSC_SUCCESS); 6538 } 6539 6540 /*@C 6541 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6542 6543 Not collective 6544 6545 Input Parameters: 6546 + dm - The `DM` 6547 . section - The section describing the layout in `v`, or `NULL` to use the default section 6548 . v - The local vector 6549 . point - The point in the `DM` 6550 . csize - The number of values in the closure, or `NULL` 6551 - values - The array of values, which is a borrowed array and should not be freed 6552 6553 Level: intermediate 6554 6555 Note: 6556 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6557 6558 Fortran Notes: 6559 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6560 6561 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6562 @*/ 6563 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6564 { 6565 PetscInt size = 0; 6566 6567 PetscFunctionBegin; 6568 /* Should work without recalculating size */ 6569 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6570 *values = NULL; 6571 PetscFunctionReturn(PETSC_SUCCESS); 6572 } 6573 6574 static inline void add(PetscScalar *x, PetscScalar y) 6575 { 6576 *x += y; 6577 } 6578 static inline void insert(PetscScalar *x, PetscScalar y) 6579 { 6580 *x = y; 6581 } 6582 6583 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[]) 6584 { 6585 PetscInt cdof; /* The number of constraints on this point */ 6586 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6587 PetscScalar *a; 6588 PetscInt off, cind = 0, k; 6589 6590 PetscFunctionBegin; 6591 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6592 PetscCall(PetscSectionGetOffset(section, point, &off)); 6593 a = &array[off]; 6594 if (!cdof || setBC) { 6595 if (clperm) { 6596 if (perm) { 6597 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6598 } else { 6599 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6600 } 6601 } else { 6602 if (perm) { 6603 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6604 } else { 6605 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6606 } 6607 } 6608 } else { 6609 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6610 if (clperm) { 6611 if (perm) { 6612 for (k = 0; k < dof; ++k) { 6613 if ((cind < cdof) && (k == cdofs[cind])) { 6614 ++cind; 6615 continue; 6616 } 6617 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6618 } 6619 } else { 6620 for (k = 0; k < dof; ++k) { 6621 if ((cind < cdof) && (k == cdofs[cind])) { 6622 ++cind; 6623 continue; 6624 } 6625 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6626 } 6627 } 6628 } else { 6629 if (perm) { 6630 for (k = 0; k < dof; ++k) { 6631 if ((cind < cdof) && (k == cdofs[cind])) { 6632 ++cind; 6633 continue; 6634 } 6635 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6636 } 6637 } else { 6638 for (k = 0; k < dof; ++k) { 6639 if ((cind < cdof) && (k == cdofs[cind])) { 6640 ++cind; 6641 continue; 6642 } 6643 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6644 } 6645 } 6646 } 6647 } 6648 PetscFunctionReturn(PETSC_SUCCESS); 6649 } 6650 6651 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[]) 6652 { 6653 PetscInt cdof; /* The number of constraints on this point */ 6654 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6655 PetscScalar *a; 6656 PetscInt off, cind = 0, k; 6657 6658 PetscFunctionBegin; 6659 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6660 PetscCall(PetscSectionGetOffset(section, point, &off)); 6661 a = &array[off]; 6662 if (cdof) { 6663 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6664 if (clperm) { 6665 if (perm) { 6666 for (k = 0; k < dof; ++k) { 6667 if ((cind < cdof) && (k == cdofs[cind])) { 6668 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6669 cind++; 6670 } 6671 } 6672 } else { 6673 for (k = 0; k < dof; ++k) { 6674 if ((cind < cdof) && (k == cdofs[cind])) { 6675 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6676 cind++; 6677 } 6678 } 6679 } 6680 } else { 6681 if (perm) { 6682 for (k = 0; k < dof; ++k) { 6683 if ((cind < cdof) && (k == cdofs[cind])) { 6684 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6685 cind++; 6686 } 6687 } 6688 } else { 6689 for (k = 0; k < dof; ++k) { 6690 if ((cind < cdof) && (k == cdofs[cind])) { 6691 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6692 cind++; 6693 } 6694 } 6695 } 6696 } 6697 } 6698 PetscFunctionReturn(PETSC_SUCCESS); 6699 } 6700 6701 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[]) 6702 { 6703 PetscScalar *a; 6704 PetscInt fdof, foff, fcdof, foffset = *offset; 6705 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6706 PetscInt cind = 0, b; 6707 6708 PetscFunctionBegin; 6709 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6710 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6711 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6712 a = &array[foff]; 6713 if (!fcdof || setBC) { 6714 if (clperm) { 6715 if (perm) { 6716 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6717 } else { 6718 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6719 } 6720 } else { 6721 if (perm) { 6722 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6723 } else { 6724 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6725 } 6726 } 6727 } else { 6728 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6729 if (clperm) { 6730 if (perm) { 6731 for (b = 0; b < fdof; b++) { 6732 if ((cind < fcdof) && (b == fcdofs[cind])) { 6733 ++cind; 6734 continue; 6735 } 6736 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6737 } 6738 } else { 6739 for (b = 0; b < fdof; b++) { 6740 if ((cind < fcdof) && (b == fcdofs[cind])) { 6741 ++cind; 6742 continue; 6743 } 6744 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6745 } 6746 } 6747 } else { 6748 if (perm) { 6749 for (b = 0; b < fdof; b++) { 6750 if ((cind < fcdof) && (b == fcdofs[cind])) { 6751 ++cind; 6752 continue; 6753 } 6754 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6755 } 6756 } else { 6757 for (b = 0; b < fdof; b++) { 6758 if ((cind < fcdof) && (b == fcdofs[cind])) { 6759 ++cind; 6760 continue; 6761 } 6762 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6763 } 6764 } 6765 } 6766 } 6767 *offset += fdof; 6768 PetscFunctionReturn(PETSC_SUCCESS); 6769 } 6770 6771 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[]) 6772 { 6773 PetscScalar *a; 6774 PetscInt fdof, foff, fcdof, foffset = *offset; 6775 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6776 PetscInt Nc, cind = 0, ncind = 0, b; 6777 PetscBool ncSet, fcSet; 6778 6779 PetscFunctionBegin; 6780 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6781 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6782 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6783 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6784 a = &array[foff]; 6785 if (fcdof) { 6786 /* We just override fcdof and fcdofs with Ncc and comps */ 6787 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6788 if (clperm) { 6789 if (perm) { 6790 if (comps) { 6791 for (b = 0; b < fdof; b++) { 6792 ncSet = fcSet = PETSC_FALSE; 6793 if (b % Nc == comps[ncind]) { 6794 ncind = (ncind + 1) % Ncc; 6795 ncSet = PETSC_TRUE; 6796 } 6797 if ((cind < fcdof) && (b == fcdofs[cind])) { 6798 ++cind; 6799 fcSet = PETSC_TRUE; 6800 } 6801 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6802 } 6803 } else { 6804 for (b = 0; b < fdof; b++) { 6805 if ((cind < fcdof) && (b == fcdofs[cind])) { 6806 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6807 ++cind; 6808 } 6809 } 6810 } 6811 } else { 6812 if (comps) { 6813 for (b = 0; b < fdof; b++) { 6814 ncSet = fcSet = PETSC_FALSE; 6815 if (b % Nc == comps[ncind]) { 6816 ncind = (ncind + 1) % Ncc; 6817 ncSet = PETSC_TRUE; 6818 } 6819 if ((cind < fcdof) && (b == fcdofs[cind])) { 6820 ++cind; 6821 fcSet = PETSC_TRUE; 6822 } 6823 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6824 } 6825 } else { 6826 for (b = 0; b < fdof; b++) { 6827 if ((cind < fcdof) && (b == fcdofs[cind])) { 6828 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6829 ++cind; 6830 } 6831 } 6832 } 6833 } 6834 } else { 6835 if (perm) { 6836 if (comps) { 6837 for (b = 0; b < fdof; b++) { 6838 ncSet = fcSet = PETSC_FALSE; 6839 if (b % Nc == comps[ncind]) { 6840 ncind = (ncind + 1) % Ncc; 6841 ncSet = PETSC_TRUE; 6842 } 6843 if ((cind < fcdof) && (b == fcdofs[cind])) { 6844 ++cind; 6845 fcSet = PETSC_TRUE; 6846 } 6847 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6848 } 6849 } else { 6850 for (b = 0; b < fdof; b++) { 6851 if ((cind < fcdof) && (b == fcdofs[cind])) { 6852 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6853 ++cind; 6854 } 6855 } 6856 } 6857 } else { 6858 if (comps) { 6859 for (b = 0; b < fdof; b++) { 6860 ncSet = fcSet = PETSC_FALSE; 6861 if (b % Nc == comps[ncind]) { 6862 ncind = (ncind + 1) % Ncc; 6863 ncSet = PETSC_TRUE; 6864 } 6865 if ((cind < fcdof) && (b == fcdofs[cind])) { 6866 ++cind; 6867 fcSet = PETSC_TRUE; 6868 } 6869 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6870 } 6871 } else { 6872 for (b = 0; b < fdof; b++) { 6873 if ((cind < fcdof) && (b == fcdofs[cind])) { 6874 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6875 ++cind; 6876 } 6877 } 6878 } 6879 } 6880 } 6881 } 6882 *offset += fdof; 6883 PetscFunctionReturn(PETSC_SUCCESS); 6884 } 6885 6886 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6887 { 6888 PetscScalar *array; 6889 const PetscInt *cone, *coneO; 6890 PetscInt pStart, pEnd, p, numPoints, off, dof; 6891 6892 PetscFunctionBeginHot; 6893 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6894 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6895 PetscCall(DMPlexGetCone(dm, point, &cone)); 6896 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6897 PetscCall(VecGetArray(v, &array)); 6898 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6899 const PetscInt cp = !p ? point : cone[p - 1]; 6900 const PetscInt o = !p ? 0 : coneO[p - 1]; 6901 6902 if ((cp < pStart) || (cp >= pEnd)) { 6903 dof = 0; 6904 continue; 6905 } 6906 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6907 /* ADD_VALUES */ 6908 { 6909 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6910 PetscScalar *a; 6911 PetscInt cdof, coff, cind = 0, k; 6912 6913 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6914 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6915 a = &array[coff]; 6916 if (!cdof) { 6917 if (o >= 0) { 6918 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6919 } else { 6920 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6921 } 6922 } else { 6923 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6924 if (o >= 0) { 6925 for (k = 0; k < dof; ++k) { 6926 if ((cind < cdof) && (k == cdofs[cind])) { 6927 ++cind; 6928 continue; 6929 } 6930 a[k] += values[off + k]; 6931 } 6932 } else { 6933 for (k = 0; k < dof; ++k) { 6934 if ((cind < cdof) && (k == cdofs[cind])) { 6935 ++cind; 6936 continue; 6937 } 6938 a[k] += values[off + dof - k - 1]; 6939 } 6940 } 6941 } 6942 } 6943 } 6944 PetscCall(VecRestoreArray(v, &array)); 6945 PetscFunctionReturn(PETSC_SUCCESS); 6946 } 6947 6948 /*@C 6949 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6950 6951 Not collective 6952 6953 Input Parameters: 6954 + dm - The `DM` 6955 . section - The section describing the layout in `v`, or `NULL` to use the default section 6956 . v - The local vector 6957 . point - The point in the `DM` 6958 . values - The array of values 6959 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6960 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6961 6962 Level: intermediate 6963 6964 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6965 @*/ 6966 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6967 { 6968 PetscSection clSection; 6969 IS clPoints; 6970 PetscScalar *array; 6971 PetscInt *points = NULL; 6972 const PetscInt *clp, *clperm = NULL; 6973 PetscInt depth, numFields, numPoints, p, clsize; 6974 6975 PetscFunctionBeginHot; 6976 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6977 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6978 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6979 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6980 PetscCall(DMPlexGetDepth(dm, &depth)); 6981 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6982 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6983 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6984 PetscFunctionReturn(PETSC_SUCCESS); 6985 } 6986 /* Get points */ 6987 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6988 for (clsize = 0, p = 0; p < numPoints; p++) { 6989 PetscInt dof; 6990 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6991 clsize += dof; 6992 } 6993 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6994 /* Get array */ 6995 PetscCall(VecGetArray(v, &array)); 6996 /* Get values */ 6997 if (numFields > 0) { 6998 PetscInt offset = 0, f; 6999 for (f = 0; f < numFields; ++f) { 7000 const PetscInt **perms = NULL; 7001 const PetscScalar **flips = NULL; 7002 7003 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7004 switch (mode) { 7005 case INSERT_VALUES: 7006 for (p = 0; p < numPoints; p++) { 7007 const PetscInt point = points[2 * p]; 7008 const PetscInt *perm = perms ? perms[p] : NULL; 7009 const PetscScalar *flip = flips ? flips[p] : NULL; 7010 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7011 } 7012 break; 7013 case INSERT_ALL_VALUES: 7014 for (p = 0; p < numPoints; p++) { 7015 const PetscInt point = points[2 * p]; 7016 const PetscInt *perm = perms ? perms[p] : NULL; 7017 const PetscScalar *flip = flips ? flips[p] : NULL; 7018 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7019 } 7020 break; 7021 case INSERT_BC_VALUES: 7022 for (p = 0; p < numPoints; p++) { 7023 const PetscInt point = points[2 * p]; 7024 const PetscInt *perm = perms ? perms[p] : NULL; 7025 const PetscScalar *flip = flips ? flips[p] : NULL; 7026 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7027 } 7028 break; 7029 case ADD_VALUES: 7030 for (p = 0; p < numPoints; p++) { 7031 const PetscInt point = points[2 * p]; 7032 const PetscInt *perm = perms ? perms[p] : NULL; 7033 const PetscScalar *flip = flips ? flips[p] : NULL; 7034 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7035 } 7036 break; 7037 case ADD_ALL_VALUES: 7038 for (p = 0; p < numPoints; p++) { 7039 const PetscInt point = points[2 * p]; 7040 const PetscInt *perm = perms ? perms[p] : NULL; 7041 const PetscScalar *flip = flips ? flips[p] : NULL; 7042 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7043 } 7044 break; 7045 case ADD_BC_VALUES: 7046 for (p = 0; p < numPoints; p++) { 7047 const PetscInt point = points[2 * p]; 7048 const PetscInt *perm = perms ? perms[p] : NULL; 7049 const PetscScalar *flip = flips ? flips[p] : NULL; 7050 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7051 } 7052 break; 7053 default: 7054 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7055 } 7056 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7057 } 7058 } else { 7059 PetscInt dof, off; 7060 const PetscInt **perms = NULL; 7061 const PetscScalar **flips = NULL; 7062 7063 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7064 switch (mode) { 7065 case INSERT_VALUES: 7066 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7067 const PetscInt point = points[2 * p]; 7068 const PetscInt *perm = perms ? perms[p] : NULL; 7069 const PetscScalar *flip = flips ? flips[p] : NULL; 7070 PetscCall(PetscSectionGetDof(section, point, &dof)); 7071 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7072 } 7073 break; 7074 case INSERT_ALL_VALUES: 7075 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7076 const PetscInt point = points[2 * p]; 7077 const PetscInt *perm = perms ? perms[p] : NULL; 7078 const PetscScalar *flip = flips ? flips[p] : NULL; 7079 PetscCall(PetscSectionGetDof(section, point, &dof)); 7080 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7081 } 7082 break; 7083 case INSERT_BC_VALUES: 7084 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7085 const PetscInt point = points[2 * p]; 7086 const PetscInt *perm = perms ? perms[p] : NULL; 7087 const PetscScalar *flip = flips ? flips[p] : NULL; 7088 PetscCall(PetscSectionGetDof(section, point, &dof)); 7089 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7090 } 7091 break; 7092 case ADD_VALUES: 7093 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7094 const PetscInt point = points[2 * p]; 7095 const PetscInt *perm = perms ? perms[p] : NULL; 7096 const PetscScalar *flip = flips ? flips[p] : NULL; 7097 PetscCall(PetscSectionGetDof(section, point, &dof)); 7098 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7099 } 7100 break; 7101 case ADD_ALL_VALUES: 7102 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7103 const PetscInt point = points[2 * p]; 7104 const PetscInt *perm = perms ? perms[p] : NULL; 7105 const PetscScalar *flip = flips ? flips[p] : NULL; 7106 PetscCall(PetscSectionGetDof(section, point, &dof)); 7107 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7108 } 7109 break; 7110 case ADD_BC_VALUES: 7111 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7112 const PetscInt point = points[2 * p]; 7113 const PetscInt *perm = perms ? perms[p] : NULL; 7114 const PetscScalar *flip = flips ? flips[p] : NULL; 7115 PetscCall(PetscSectionGetDof(section, point, &dof)); 7116 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7117 } 7118 break; 7119 default: 7120 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7121 } 7122 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7123 } 7124 /* Cleanup points */ 7125 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7126 /* Cleanup array */ 7127 PetscCall(VecRestoreArray(v, &array)); 7128 PetscFunctionReturn(PETSC_SUCCESS); 7129 } 7130 7131 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7132 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7133 { 7134 PetscFunctionBegin; 7135 *contains = PETSC_TRUE; 7136 if (label) { 7137 PetscInt fdof; 7138 7139 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7140 if (!*contains) { 7141 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7142 *offset += fdof; 7143 PetscFunctionReturn(PETSC_SUCCESS); 7144 } 7145 } 7146 PetscFunctionReturn(PETSC_SUCCESS); 7147 } 7148 7149 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7150 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) 7151 { 7152 PetscSection clSection; 7153 IS clPoints; 7154 PetscScalar *array; 7155 PetscInt *points = NULL; 7156 const PetscInt *clp; 7157 PetscInt numFields, numPoints, p; 7158 PetscInt offset = 0, f; 7159 7160 PetscFunctionBeginHot; 7161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7162 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7163 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7164 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7165 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7166 /* Get points */ 7167 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7168 /* Get array */ 7169 PetscCall(VecGetArray(v, &array)); 7170 /* Get values */ 7171 for (f = 0; f < numFields; ++f) { 7172 const PetscInt **perms = NULL; 7173 const PetscScalar **flips = NULL; 7174 PetscBool contains; 7175 7176 if (!fieldActive[f]) { 7177 for (p = 0; p < numPoints * 2; p += 2) { 7178 PetscInt fdof; 7179 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7180 offset += fdof; 7181 } 7182 continue; 7183 } 7184 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7185 switch (mode) { 7186 case INSERT_VALUES: 7187 for (p = 0; p < numPoints; p++) { 7188 const PetscInt point = points[2 * p]; 7189 const PetscInt *perm = perms ? perms[p] : NULL; 7190 const PetscScalar *flip = flips ? flips[p] : NULL; 7191 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7192 if (!contains) continue; 7193 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7194 } 7195 break; 7196 case INSERT_ALL_VALUES: 7197 for (p = 0; p < numPoints; p++) { 7198 const PetscInt point = points[2 * p]; 7199 const PetscInt *perm = perms ? perms[p] : NULL; 7200 const PetscScalar *flip = flips ? flips[p] : NULL; 7201 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7202 if (!contains) continue; 7203 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7204 } 7205 break; 7206 case INSERT_BC_VALUES: 7207 for (p = 0; p < numPoints; p++) { 7208 const PetscInt point = points[2 * p]; 7209 const PetscInt *perm = perms ? perms[p] : NULL; 7210 const PetscScalar *flip = flips ? flips[p] : NULL; 7211 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7212 if (!contains) continue; 7213 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7214 } 7215 break; 7216 case ADD_VALUES: 7217 for (p = 0; p < numPoints; p++) { 7218 const PetscInt point = points[2 * p]; 7219 const PetscInt *perm = perms ? perms[p] : NULL; 7220 const PetscScalar *flip = flips ? flips[p] : NULL; 7221 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7222 if (!contains) continue; 7223 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7224 } 7225 break; 7226 case ADD_ALL_VALUES: 7227 for (p = 0; p < numPoints; p++) { 7228 const PetscInt point = points[2 * p]; 7229 const PetscInt *perm = perms ? perms[p] : NULL; 7230 const PetscScalar *flip = flips ? flips[p] : NULL; 7231 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7232 if (!contains) continue; 7233 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7234 } 7235 break; 7236 default: 7237 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7238 } 7239 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7240 } 7241 /* Cleanup points */ 7242 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7243 /* Cleanup array */ 7244 PetscCall(VecRestoreArray(v, &array)); 7245 PetscFunctionReturn(PETSC_SUCCESS); 7246 } 7247 7248 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7249 { 7250 PetscMPIInt rank; 7251 PetscInt i, j; 7252 7253 PetscFunctionBegin; 7254 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7255 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7256 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7257 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7258 numCIndices = numCIndices ? numCIndices : numRIndices; 7259 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7260 for (i = 0; i < numRIndices; i++) { 7261 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7262 for (j = 0; j < numCIndices; j++) { 7263 #if defined(PETSC_USE_COMPLEX) 7264 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7265 #else 7266 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7267 #endif 7268 } 7269 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7270 } 7271 PetscFunctionReturn(PETSC_SUCCESS); 7272 } 7273 7274 /* 7275 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7276 7277 Input Parameters: 7278 + section - The section for this data layout 7279 . islocal - Is the section (and thus indices being requested) local or global? 7280 . point - The point contributing dofs with these indices 7281 . off - The global offset of this point 7282 . loff - The local offset of each field 7283 . setBC - The flag determining whether to include indices of boundary values 7284 . perm - A permutation of the dofs on this point, or NULL 7285 - indperm - A permutation of the entire indices array, or NULL 7286 7287 Output Parameter: 7288 . indices - Indices for dofs on this point 7289 7290 Level: developer 7291 7292 Note: The indices could be local or global, depending on the value of 'off'. 7293 */ 7294 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7295 { 7296 PetscInt dof; /* The number of unknowns on this point */ 7297 PetscInt cdof; /* The number of constraints on this point */ 7298 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7299 PetscInt cind = 0, k; 7300 7301 PetscFunctionBegin; 7302 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7303 PetscCall(PetscSectionGetDof(section, point, &dof)); 7304 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7305 if (!cdof || setBC) { 7306 for (k = 0; k < dof; ++k) { 7307 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7308 const PetscInt ind = indperm ? indperm[preind] : preind; 7309 7310 indices[ind] = off + k; 7311 } 7312 } else { 7313 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7314 for (k = 0; k < dof; ++k) { 7315 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7316 const PetscInt ind = indperm ? indperm[preind] : preind; 7317 7318 if ((cind < cdof) && (k == cdofs[cind])) { 7319 /* Insert check for returning constrained indices */ 7320 indices[ind] = -(off + k + 1); 7321 ++cind; 7322 } else { 7323 indices[ind] = off + k - (islocal ? 0 : cind); 7324 } 7325 } 7326 } 7327 *loff += dof; 7328 PetscFunctionReturn(PETSC_SUCCESS); 7329 } 7330 7331 /* 7332 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7333 7334 Input Parameters: 7335 + section - a section (global or local) 7336 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7337 . point - point within section 7338 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7339 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7340 . setBC - identify constrained (boundary condition) points via involution. 7341 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7342 . permsoff - offset 7343 - indperm - index permutation 7344 7345 Output Parameter: 7346 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7347 . indices - array to hold indices (as defined by section) of each dof associated with point 7348 7349 Notes: 7350 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7351 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7352 in the local vector. 7353 7354 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7355 significant). It is invalid to call with a global section and setBC=true. 7356 7357 Developer Note: 7358 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7359 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7360 offset could be obtained from the section instead of passing it explicitly as we do now. 7361 7362 Example: 7363 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7364 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7365 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7366 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. 7367 7368 Level: developer 7369 */ 7370 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[]) 7371 { 7372 PetscInt numFields, foff, f; 7373 7374 PetscFunctionBegin; 7375 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7376 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7377 for (f = 0, foff = 0; f < numFields; ++f) { 7378 PetscInt fdof, cfdof; 7379 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7380 PetscInt cind = 0, b; 7381 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7382 7383 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7384 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7385 if (!cfdof || setBC) { 7386 for (b = 0; b < fdof; ++b) { 7387 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7388 const PetscInt ind = indperm ? indperm[preind] : preind; 7389 7390 indices[ind] = off + foff + b; 7391 } 7392 } else { 7393 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7394 for (b = 0; b < fdof; ++b) { 7395 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7396 const PetscInt ind = indperm ? indperm[preind] : preind; 7397 7398 if ((cind < cfdof) && (b == fcdofs[cind])) { 7399 indices[ind] = -(off + foff + b + 1); 7400 ++cind; 7401 } else { 7402 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7403 } 7404 } 7405 } 7406 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7407 foffs[f] += fdof; 7408 } 7409 PetscFunctionReturn(PETSC_SUCCESS); 7410 } 7411 7412 /* 7413 This version believes the globalSection offsets for each field, rather than just the point offset 7414 7415 . foffs - The offset into 'indices' for each field, since it is segregated by field 7416 7417 Notes: 7418 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7419 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7420 */ 7421 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7422 { 7423 PetscInt numFields, foff, f; 7424 7425 PetscFunctionBegin; 7426 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7427 for (f = 0; f < numFields; ++f) { 7428 PetscInt fdof, cfdof; 7429 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7430 PetscInt cind = 0, b; 7431 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7432 7433 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7434 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7435 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7436 if (!cfdof) { 7437 for (b = 0; b < fdof; ++b) { 7438 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7439 const PetscInt ind = indperm ? indperm[preind] : preind; 7440 7441 indices[ind] = foff + b; 7442 } 7443 } else { 7444 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7445 for (b = 0; b < fdof; ++b) { 7446 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7447 const PetscInt ind = indperm ? indperm[preind] : preind; 7448 7449 if ((cind < cfdof) && (b == fcdofs[cind])) { 7450 indices[ind] = -(foff + b + 1); 7451 ++cind; 7452 } else { 7453 indices[ind] = foff + b - cind; 7454 } 7455 } 7456 } 7457 foffs[f] += fdof; 7458 } 7459 PetscFunctionReturn(PETSC_SUCCESS); 7460 } 7461 7462 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) 7463 { 7464 Mat cMat; 7465 PetscSection aSec, cSec; 7466 IS aIS; 7467 PetscInt aStart = -1, aEnd = -1; 7468 const PetscInt *anchors; 7469 PetscInt numFields, f, p, q, newP = 0; 7470 PetscInt newNumPoints = 0, newNumIndices = 0; 7471 PetscInt *newPoints, *indices, *newIndices; 7472 PetscInt maxAnchor, maxDof; 7473 PetscInt newOffsets[32]; 7474 PetscInt *pointMatOffsets[32]; 7475 PetscInt *newPointOffsets[32]; 7476 PetscScalar *pointMat[32]; 7477 PetscScalar *newValues = NULL, *tmpValues; 7478 PetscBool anyConstrained = PETSC_FALSE; 7479 7480 PetscFunctionBegin; 7481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7482 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7483 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7484 7485 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7486 /* if there are point-to-point constraints */ 7487 if (aSec) { 7488 PetscCall(PetscArrayzero(newOffsets, 32)); 7489 PetscCall(ISGetIndices(aIS, &anchors)); 7490 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7491 /* figure out how many points are going to be in the new element matrix 7492 * (we allow double counting, because it's all just going to be summed 7493 * into the global matrix anyway) */ 7494 for (p = 0; p < 2 * numPoints; p += 2) { 7495 PetscInt b = points[p]; 7496 PetscInt bDof = 0, bSecDof; 7497 7498 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7499 if (!bSecDof) continue; 7500 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7501 if (bDof) { 7502 /* this point is constrained */ 7503 /* it is going to be replaced by its anchors */ 7504 PetscInt bOff, q; 7505 7506 anyConstrained = PETSC_TRUE; 7507 newNumPoints += bDof; 7508 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7509 for (q = 0; q < bDof; q++) { 7510 PetscInt a = anchors[bOff + q]; 7511 PetscInt aDof; 7512 7513 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7514 newNumIndices += aDof; 7515 for (f = 0; f < numFields; ++f) { 7516 PetscInt fDof; 7517 7518 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7519 newOffsets[f + 1] += fDof; 7520 } 7521 } 7522 } else { 7523 /* this point is not constrained */ 7524 newNumPoints++; 7525 newNumIndices += bSecDof; 7526 for (f = 0; f < numFields; ++f) { 7527 PetscInt fDof; 7528 7529 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7530 newOffsets[f + 1] += fDof; 7531 } 7532 } 7533 } 7534 } 7535 if (!anyConstrained) { 7536 if (outNumPoints) *outNumPoints = 0; 7537 if (outNumIndices) *outNumIndices = 0; 7538 if (outPoints) *outPoints = NULL; 7539 if (outValues) *outValues = NULL; 7540 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7541 PetscFunctionReturn(PETSC_SUCCESS); 7542 } 7543 7544 if (outNumPoints) *outNumPoints = newNumPoints; 7545 if (outNumIndices) *outNumIndices = newNumIndices; 7546 7547 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7548 7549 if (!outPoints && !outValues) { 7550 if (offsets) { 7551 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7552 } 7553 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7554 PetscFunctionReturn(PETSC_SUCCESS); 7555 } 7556 7557 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7558 7559 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7560 7561 /* workspaces */ 7562 if (numFields) { 7563 for (f = 0; f < numFields; f++) { 7564 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7565 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7566 } 7567 } else { 7568 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7569 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7570 } 7571 7572 /* get workspaces for the point-to-point matrices */ 7573 if (numFields) { 7574 PetscInt totalOffset, totalMatOffset; 7575 7576 for (p = 0; p < numPoints; p++) { 7577 PetscInt b = points[2 * p]; 7578 PetscInt bDof = 0, bSecDof; 7579 7580 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7581 if (!bSecDof) { 7582 for (f = 0; f < numFields; f++) { 7583 newPointOffsets[f][p + 1] = 0; 7584 pointMatOffsets[f][p + 1] = 0; 7585 } 7586 continue; 7587 } 7588 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7589 if (bDof) { 7590 for (f = 0; f < numFields; f++) { 7591 PetscInt fDof, q, bOff, allFDof = 0; 7592 7593 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7594 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7595 for (q = 0; q < bDof; q++) { 7596 PetscInt a = anchors[bOff + q]; 7597 PetscInt aFDof; 7598 7599 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7600 allFDof += aFDof; 7601 } 7602 newPointOffsets[f][p + 1] = allFDof; 7603 pointMatOffsets[f][p + 1] = fDof * allFDof; 7604 } 7605 } else { 7606 for (f = 0; f < numFields; f++) { 7607 PetscInt fDof; 7608 7609 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7610 newPointOffsets[f][p + 1] = fDof; 7611 pointMatOffsets[f][p + 1] = 0; 7612 } 7613 } 7614 } 7615 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7616 newPointOffsets[f][0] = totalOffset; 7617 pointMatOffsets[f][0] = totalMatOffset; 7618 for (p = 0; p < numPoints; p++) { 7619 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7620 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7621 } 7622 totalOffset = newPointOffsets[f][numPoints]; 7623 totalMatOffset = pointMatOffsets[f][numPoints]; 7624 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7625 } 7626 } else { 7627 for (p = 0; p < numPoints; p++) { 7628 PetscInt b = points[2 * p]; 7629 PetscInt bDof = 0, bSecDof; 7630 7631 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7632 if (!bSecDof) { 7633 newPointOffsets[0][p + 1] = 0; 7634 pointMatOffsets[0][p + 1] = 0; 7635 continue; 7636 } 7637 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7638 if (bDof) { 7639 PetscInt bOff, q, allDof = 0; 7640 7641 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7642 for (q = 0; q < bDof; q++) { 7643 PetscInt a = anchors[bOff + q], aDof; 7644 7645 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7646 allDof += aDof; 7647 } 7648 newPointOffsets[0][p + 1] = allDof; 7649 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7650 } else { 7651 newPointOffsets[0][p + 1] = bSecDof; 7652 pointMatOffsets[0][p + 1] = 0; 7653 } 7654 } 7655 newPointOffsets[0][0] = 0; 7656 pointMatOffsets[0][0] = 0; 7657 for (p = 0; p < numPoints; p++) { 7658 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7659 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7660 } 7661 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7662 } 7663 7664 /* output arrays */ 7665 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7666 7667 /* get the point-to-point matrices; construct newPoints */ 7668 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7669 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7670 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7671 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7672 if (numFields) { 7673 for (p = 0, newP = 0; p < numPoints; p++) { 7674 PetscInt b = points[2 * p]; 7675 PetscInt o = points[2 * p + 1]; 7676 PetscInt bDof = 0, bSecDof; 7677 7678 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7679 if (!bSecDof) continue; 7680 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7681 if (bDof) { 7682 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7683 7684 fStart[0] = 0; 7685 fEnd[0] = 0; 7686 for (f = 0; f < numFields; f++) { 7687 PetscInt fDof; 7688 7689 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7690 fStart[f + 1] = fStart[f] + fDof; 7691 fEnd[f + 1] = fStart[f + 1]; 7692 } 7693 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7694 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7695 7696 fAnchorStart[0] = 0; 7697 fAnchorEnd[0] = 0; 7698 for (f = 0; f < numFields; f++) { 7699 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7700 7701 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7702 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7703 } 7704 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7705 for (q = 0; q < bDof; q++) { 7706 PetscInt a = anchors[bOff + q], aOff; 7707 7708 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7709 newPoints[2 * (newP + q)] = a; 7710 newPoints[2 * (newP + q) + 1] = 0; 7711 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7712 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7713 } 7714 newP += bDof; 7715 7716 if (outValues) { 7717 /* get the point-to-point submatrix */ 7718 for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p])); 7719 } 7720 } else { 7721 newPoints[2 * newP] = b; 7722 newPoints[2 * newP + 1] = o; 7723 newP++; 7724 } 7725 } 7726 } else { 7727 for (p = 0; p < numPoints; p++) { 7728 PetscInt b = points[2 * p]; 7729 PetscInt o = points[2 * p + 1]; 7730 PetscInt bDof = 0, bSecDof; 7731 7732 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7733 if (!bSecDof) continue; 7734 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7735 if (bDof) { 7736 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7737 7738 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7739 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7740 7741 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7742 for (q = 0; q < bDof; q++) { 7743 PetscInt a = anchors[bOff + q], aOff; 7744 7745 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7746 7747 newPoints[2 * (newP + q)] = a; 7748 newPoints[2 * (newP + q) + 1] = 0; 7749 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7750 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7751 } 7752 newP += bDof; 7753 7754 /* get the point-to-point submatrix */ 7755 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7756 } else { 7757 newPoints[2 * newP] = b; 7758 newPoints[2 * newP + 1] = o; 7759 newP++; 7760 } 7761 } 7762 } 7763 7764 if (outValues) { 7765 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7766 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7767 /* multiply constraints on the right */ 7768 if (numFields) { 7769 for (f = 0; f < numFields; f++) { 7770 PetscInt oldOff = offsets[f]; 7771 7772 for (p = 0; p < numPoints; p++) { 7773 PetscInt cStart = newPointOffsets[f][p]; 7774 PetscInt b = points[2 * p]; 7775 PetscInt c, r, k; 7776 PetscInt dof; 7777 7778 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7779 if (!dof) continue; 7780 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7781 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7782 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7783 7784 for (r = 0; r < numIndices; r++) { 7785 for (c = 0; c < nCols; c++) { 7786 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7787 } 7788 } 7789 } else { 7790 /* copy this column as is */ 7791 for (r = 0; r < numIndices; r++) { 7792 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7793 } 7794 } 7795 oldOff += dof; 7796 } 7797 } 7798 } else { 7799 PetscInt oldOff = 0; 7800 for (p = 0; p < numPoints; p++) { 7801 PetscInt cStart = newPointOffsets[0][p]; 7802 PetscInt b = points[2 * p]; 7803 PetscInt c, r, k; 7804 PetscInt dof; 7805 7806 PetscCall(PetscSectionGetDof(section, b, &dof)); 7807 if (!dof) continue; 7808 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7809 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7810 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7811 7812 for (r = 0; r < numIndices; r++) { 7813 for (c = 0; c < nCols; c++) { 7814 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7815 } 7816 } 7817 } else { 7818 /* copy this column as is */ 7819 for (r = 0; r < numIndices; r++) { 7820 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7821 } 7822 } 7823 oldOff += dof; 7824 } 7825 } 7826 7827 if (multiplyLeft) { 7828 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7829 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7830 /* multiply constraints transpose on the left */ 7831 if (numFields) { 7832 for (f = 0; f < numFields; f++) { 7833 PetscInt oldOff = offsets[f]; 7834 7835 for (p = 0; p < numPoints; p++) { 7836 PetscInt rStart = newPointOffsets[f][p]; 7837 PetscInt b = points[2 * p]; 7838 PetscInt c, r, k; 7839 PetscInt dof; 7840 7841 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7842 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7843 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7844 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7845 7846 for (r = 0; r < nRows; r++) { 7847 for (c = 0; c < newNumIndices; c++) { 7848 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7849 } 7850 } 7851 } else { 7852 /* copy this row as is */ 7853 for (r = 0; r < dof; r++) { 7854 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7855 } 7856 } 7857 oldOff += dof; 7858 } 7859 } 7860 } else { 7861 PetscInt oldOff = 0; 7862 7863 for (p = 0; p < numPoints; p++) { 7864 PetscInt rStart = newPointOffsets[0][p]; 7865 PetscInt b = points[2 * p]; 7866 PetscInt c, r, k; 7867 PetscInt dof; 7868 7869 PetscCall(PetscSectionGetDof(section, b, &dof)); 7870 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7871 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7872 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7873 7874 for (r = 0; r < nRows; r++) { 7875 for (c = 0; c < newNumIndices; c++) { 7876 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7877 } 7878 } 7879 } else { 7880 /* copy this row as is */ 7881 for (r = 0; r < dof; r++) { 7882 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7883 } 7884 } 7885 oldOff += dof; 7886 } 7887 } 7888 7889 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7890 } else { 7891 newValues = tmpValues; 7892 } 7893 } 7894 7895 /* clean up */ 7896 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7897 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7898 7899 if (numFields) { 7900 for (f = 0; f < numFields; f++) { 7901 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7902 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7903 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7904 } 7905 } else { 7906 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7907 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7908 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7909 } 7910 PetscCall(ISRestoreIndices(aIS, &anchors)); 7911 7912 /* output */ 7913 if (outPoints) { 7914 *outPoints = newPoints; 7915 } else { 7916 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7917 } 7918 if (outValues) *outValues = newValues; 7919 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7920 PetscFunctionReturn(PETSC_SUCCESS); 7921 } 7922 7923 /*@C 7924 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7925 7926 Not collective 7927 7928 Input Parameters: 7929 + dm - The `DM` 7930 . section - The `PetscSection` describing the points (a local section) 7931 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7932 . point - The point defining the closure 7933 - useClPerm - Use the closure point permutation if available 7934 7935 Output Parameters: 7936 + numIndices - The number of dof indices in the closure of point with the input sections 7937 . indices - The dof indices 7938 . outOffsets - Array to write the field offsets into, or `NULL` 7939 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7940 7941 Level: advanced 7942 7943 Notes: 7944 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7945 7946 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7947 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7948 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7949 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7950 indices (with the above semantics) are implied. 7951 7952 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7953 `PetscSection`, `DMGetGlobalSection()` 7954 @*/ 7955 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7956 { 7957 /* Closure ordering */ 7958 PetscSection clSection; 7959 IS clPoints; 7960 const PetscInt *clp; 7961 PetscInt *points; 7962 const PetscInt *clperm = NULL; 7963 /* Dof permutation and sign flips */ 7964 const PetscInt **perms[32] = {NULL}; 7965 const PetscScalar **flips[32] = {NULL}; 7966 PetscScalar *valCopy = NULL; 7967 /* Hanging node constraints */ 7968 PetscInt *pointsC = NULL; 7969 PetscScalar *valuesC = NULL; 7970 PetscInt NclC, NiC; 7971 7972 PetscInt *idx; 7973 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7974 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7975 7976 PetscFunctionBeginHot; 7977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7978 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7979 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7980 if (numIndices) PetscAssertPointer(numIndices, 6); 7981 if (indices) PetscAssertPointer(indices, 7); 7982 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7983 if (values) PetscAssertPointer(values, 9); 7984 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7985 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7986 PetscCall(PetscArrayzero(offsets, 32)); 7987 /* 1) Get points in closure */ 7988 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7989 if (useClPerm) { 7990 PetscInt depth, clsize; 7991 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7992 for (clsize = 0, p = 0; p < Ncl; p++) { 7993 PetscInt dof; 7994 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7995 clsize += dof; 7996 } 7997 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7998 } 7999 /* 2) Get number of indices on these points and field offsets from section */ 8000 for (p = 0; p < Ncl * 2; p += 2) { 8001 PetscInt dof, fdof; 8002 8003 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8004 for (f = 0; f < Nf; ++f) { 8005 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8006 offsets[f + 1] += fdof; 8007 } 8008 Ni += dof; 8009 } 8010 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8011 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8012 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8013 for (f = 0; f < PetscMax(1, Nf); ++f) { 8014 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8015 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8016 /* may need to apply sign changes to the element matrix */ 8017 if (values && flips[f]) { 8018 PetscInt foffset = offsets[f]; 8019 8020 for (p = 0; p < Ncl; ++p) { 8021 PetscInt pnt = points[2 * p], fdof; 8022 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8023 8024 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8025 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8026 if (flip) { 8027 PetscInt i, j, k; 8028 8029 if (!valCopy) { 8030 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8031 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8032 *values = valCopy; 8033 } 8034 for (i = 0; i < fdof; ++i) { 8035 PetscScalar fval = flip[i]; 8036 8037 for (k = 0; k < Ni; ++k) { 8038 valCopy[Ni * (foffset + i) + k] *= fval; 8039 valCopy[Ni * k + (foffset + i)] *= fval; 8040 } 8041 } 8042 } 8043 foffset += fdof; 8044 } 8045 } 8046 } 8047 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8048 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 8049 if (NclC) { 8050 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8051 for (f = 0; f < PetscMax(1, Nf); ++f) { 8052 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8053 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8054 } 8055 for (f = 0; f < PetscMax(1, Nf); ++f) { 8056 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8057 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8058 } 8059 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8060 Ncl = NclC; 8061 Ni = NiC; 8062 points = pointsC; 8063 if (values) *values = valuesC; 8064 } 8065 /* 5) Calculate indices */ 8066 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8067 if (Nf) { 8068 PetscInt idxOff; 8069 PetscBool useFieldOffsets; 8070 8071 if (outOffsets) { 8072 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8073 } 8074 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8075 if (useFieldOffsets) { 8076 for (p = 0; p < Ncl; ++p) { 8077 const PetscInt pnt = points[p * 2]; 8078 8079 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8080 } 8081 } else { 8082 for (p = 0; p < Ncl; ++p) { 8083 const PetscInt pnt = points[p * 2]; 8084 8085 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8086 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8087 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8088 * global section. */ 8089 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8090 } 8091 } 8092 } else { 8093 PetscInt off = 0, idxOff; 8094 8095 for (p = 0; p < Ncl; ++p) { 8096 const PetscInt pnt = points[p * 2]; 8097 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8098 8099 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8100 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8101 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8102 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8103 } 8104 } 8105 /* 6) Cleanup */ 8106 for (f = 0; f < PetscMax(1, Nf); ++f) { 8107 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8108 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8109 } 8110 if (NclC) { 8111 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8112 } else { 8113 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8114 } 8115 8116 if (numIndices) *numIndices = Ni; 8117 if (indices) *indices = idx; 8118 PetscFunctionReturn(PETSC_SUCCESS); 8119 } 8120 8121 /*@C 8122 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8123 8124 Not collective 8125 8126 Input Parameters: 8127 + dm - The `DM` 8128 . section - The `PetscSection` describing the points (a local section) 8129 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8130 . point - The point defining the closure 8131 - useClPerm - Use the closure point permutation if available 8132 8133 Output Parameters: 8134 + numIndices - The number of dof indices in the closure of point with the input sections 8135 . indices - The dof indices 8136 . outOffsets - Array to write the field offsets into, or `NULL` 8137 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8138 8139 Level: advanced 8140 8141 Notes: 8142 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8143 8144 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8145 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8146 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8147 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8148 indices (with the above semantics) are implied. 8149 8150 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8151 @*/ 8152 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8153 { 8154 PetscFunctionBegin; 8155 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8156 PetscAssertPointer(indices, 7); 8157 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8158 PetscFunctionReturn(PETSC_SUCCESS); 8159 } 8160 8161 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8162 { 8163 DM_Plex *mesh = (DM_Plex *)dm->data; 8164 PetscInt *indices; 8165 PetscInt numIndices; 8166 const PetscScalar *valuesOrig = values; 8167 PetscErrorCode ierr; 8168 8169 PetscFunctionBegin; 8170 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8171 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8172 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8173 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8174 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8175 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8176 8177 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8178 8179 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8180 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8181 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8182 if (ierr) { 8183 PetscMPIInt rank; 8184 8185 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8186 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8187 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8188 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8189 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8190 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8191 } 8192 if (mesh->printFEM > 1) { 8193 PetscInt i; 8194 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8195 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8196 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8197 } 8198 8199 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8200 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8201 PetscFunctionReturn(PETSC_SUCCESS); 8202 } 8203 8204 /*@C 8205 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8206 8207 Not collective 8208 8209 Input Parameters: 8210 + dm - The `DM` 8211 . section - The section describing the layout in `v`, or `NULL` to use the default section 8212 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8213 . A - The matrix 8214 . point - The point in the `DM` 8215 . values - The array of values 8216 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8217 8218 Level: intermediate 8219 8220 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8221 @*/ 8222 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8223 { 8224 PetscFunctionBegin; 8225 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8226 PetscFunctionReturn(PETSC_SUCCESS); 8227 } 8228 8229 /*@C 8230 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8231 8232 Not collective 8233 8234 Input Parameters: 8235 + dmRow - The `DM` for the row fields 8236 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8237 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8238 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8239 . dmCol - The `DM` for the column fields 8240 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8241 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8242 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8243 . A - The matrix 8244 . point - The point in the `DM` 8245 . values - The array of values 8246 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8247 8248 Level: intermediate 8249 8250 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8251 @*/ 8252 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) 8253 { 8254 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8255 PetscInt *indicesRow, *indicesCol; 8256 PetscInt numIndicesRow, numIndicesCol; 8257 const PetscScalar *valuesOrig = values; 8258 PetscErrorCode ierr; 8259 8260 PetscFunctionBegin; 8261 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8262 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8263 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8264 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8265 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8266 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8267 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8268 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8269 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8270 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8271 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8272 8273 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8274 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8275 8276 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8277 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8278 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8279 if (ierr) { 8280 PetscMPIInt rank; 8281 8282 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8283 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8284 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8285 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8286 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8287 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8288 } 8289 8290 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8291 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8292 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8293 PetscFunctionReturn(PETSC_SUCCESS); 8294 } 8295 8296 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8297 { 8298 DM_Plex *mesh = (DM_Plex *)dmf->data; 8299 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8300 PetscInt *cpoints = NULL; 8301 PetscInt *findices, *cindices; 8302 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8303 PetscInt foffsets[32], coffsets[32]; 8304 DMPolytopeType ct; 8305 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8306 PetscErrorCode ierr; 8307 8308 PetscFunctionBegin; 8309 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8310 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8311 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8312 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8313 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8314 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8315 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8316 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8317 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8318 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8319 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8320 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8321 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8322 PetscCall(PetscArrayzero(foffsets, 32)); 8323 PetscCall(PetscArrayzero(coffsets, 32)); 8324 /* Column indices */ 8325 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8326 maxFPoints = numCPoints; 8327 /* Compress out points not in the section */ 8328 /* TODO: Squeeze out points with 0 dof as well */ 8329 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8330 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8331 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8332 cpoints[q * 2] = cpoints[p]; 8333 cpoints[q * 2 + 1] = cpoints[p + 1]; 8334 ++q; 8335 } 8336 } 8337 numCPoints = q; 8338 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8339 PetscInt fdof; 8340 8341 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8342 if (!dof) continue; 8343 for (f = 0; f < numFields; ++f) { 8344 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8345 coffsets[f + 1] += fdof; 8346 } 8347 numCIndices += dof; 8348 } 8349 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8350 /* Row indices */ 8351 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8352 { 8353 DMPlexTransform tr; 8354 DMPolytopeType *rct; 8355 PetscInt *rsize, *rcone, *rornt, Nt; 8356 8357 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8358 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8359 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8360 numSubcells = rsize[Nt - 1]; 8361 PetscCall(DMPlexTransformDestroy(&tr)); 8362 } 8363 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8364 for (r = 0, q = 0; r < numSubcells; ++r) { 8365 /* TODO Map from coarse to fine cells */ 8366 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8367 /* Compress out points not in the section */ 8368 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8369 for (p = 0; p < numFPoints * 2; p += 2) { 8370 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8371 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8372 if (!dof) continue; 8373 for (s = 0; s < q; ++s) 8374 if (fpoints[p] == ftotpoints[s * 2]) break; 8375 if (s < q) continue; 8376 ftotpoints[q * 2] = fpoints[p]; 8377 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8378 ++q; 8379 } 8380 } 8381 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8382 } 8383 numFPoints = q; 8384 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8385 PetscInt fdof; 8386 8387 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8388 if (!dof) continue; 8389 for (f = 0; f < numFields; ++f) { 8390 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8391 foffsets[f + 1] += fdof; 8392 } 8393 numFIndices += dof; 8394 } 8395 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8396 8397 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8398 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8399 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8400 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8401 if (numFields) { 8402 const PetscInt **permsF[32] = {NULL}; 8403 const PetscInt **permsC[32] = {NULL}; 8404 8405 for (f = 0; f < numFields; f++) { 8406 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8407 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8408 } 8409 for (p = 0; p < numFPoints; p++) { 8410 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8411 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8412 } 8413 for (p = 0; p < numCPoints; p++) { 8414 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8415 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8416 } 8417 for (f = 0; f < numFields; f++) { 8418 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8419 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8420 } 8421 } else { 8422 const PetscInt **permsF = NULL; 8423 const PetscInt **permsC = NULL; 8424 8425 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8426 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8427 for (p = 0, off = 0; p < numFPoints; p++) { 8428 const PetscInt *perm = permsF ? permsF[p] : NULL; 8429 8430 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8431 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8432 } 8433 for (p = 0, off = 0; p < numCPoints; p++) { 8434 const PetscInt *perm = permsC ? permsC[p] : NULL; 8435 8436 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8437 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8438 } 8439 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8440 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8441 } 8442 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8443 /* TODO: flips */ 8444 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8445 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8446 if (ierr) { 8447 PetscMPIInt rank; 8448 8449 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8450 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8451 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8452 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8453 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8454 } 8455 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8456 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8457 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8458 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8459 PetscFunctionReturn(PETSC_SUCCESS); 8460 } 8461 8462 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8463 { 8464 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8465 PetscInt *cpoints = NULL; 8466 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8467 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8468 DMPolytopeType ct; 8469 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8470 8471 PetscFunctionBegin; 8472 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8473 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8474 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8475 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8476 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8477 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8478 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8479 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8480 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8481 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8482 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8483 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8484 /* Column indices */ 8485 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8486 maxFPoints = numCPoints; 8487 /* Compress out points not in the section */ 8488 /* TODO: Squeeze out points with 0 dof as well */ 8489 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8490 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8491 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8492 cpoints[q * 2] = cpoints[p]; 8493 cpoints[q * 2 + 1] = cpoints[p + 1]; 8494 ++q; 8495 } 8496 } 8497 numCPoints = q; 8498 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8499 PetscInt fdof; 8500 8501 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8502 if (!dof) continue; 8503 for (f = 0; f < numFields; ++f) { 8504 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8505 coffsets[f + 1] += fdof; 8506 } 8507 numCIndices += dof; 8508 } 8509 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8510 /* Row indices */ 8511 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8512 { 8513 DMPlexTransform tr; 8514 DMPolytopeType *rct; 8515 PetscInt *rsize, *rcone, *rornt, Nt; 8516 8517 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8518 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8519 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8520 numSubcells = rsize[Nt - 1]; 8521 PetscCall(DMPlexTransformDestroy(&tr)); 8522 } 8523 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8524 for (r = 0, q = 0; r < numSubcells; ++r) { 8525 /* TODO Map from coarse to fine cells */ 8526 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8527 /* Compress out points not in the section */ 8528 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8529 for (p = 0; p < numFPoints * 2; p += 2) { 8530 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8531 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8532 if (!dof) continue; 8533 for (s = 0; s < q; ++s) 8534 if (fpoints[p] == ftotpoints[s * 2]) break; 8535 if (s < q) continue; 8536 ftotpoints[q * 2] = fpoints[p]; 8537 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8538 ++q; 8539 } 8540 } 8541 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8542 } 8543 numFPoints = q; 8544 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8545 PetscInt fdof; 8546 8547 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8548 if (!dof) continue; 8549 for (f = 0; f < numFields; ++f) { 8550 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8551 foffsets[f + 1] += fdof; 8552 } 8553 numFIndices += dof; 8554 } 8555 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8556 8557 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8558 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8559 if (numFields) { 8560 const PetscInt **permsF[32] = {NULL}; 8561 const PetscInt **permsC[32] = {NULL}; 8562 8563 for (f = 0; f < numFields; f++) { 8564 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8565 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8566 } 8567 for (p = 0; p < numFPoints; p++) { 8568 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8569 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8570 } 8571 for (p = 0; p < numCPoints; p++) { 8572 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8573 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8574 } 8575 for (f = 0; f < numFields; f++) { 8576 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8577 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8578 } 8579 } else { 8580 const PetscInt **permsF = NULL; 8581 const PetscInt **permsC = NULL; 8582 8583 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8584 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8585 for (p = 0, off = 0; p < numFPoints; p++) { 8586 const PetscInt *perm = permsF ? permsF[p] : NULL; 8587 8588 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8589 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8590 } 8591 for (p = 0, off = 0; p < numCPoints; p++) { 8592 const PetscInt *perm = permsC ? permsC[p] : NULL; 8593 8594 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8595 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8596 } 8597 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8598 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8599 } 8600 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8601 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8602 PetscFunctionReturn(PETSC_SUCCESS); 8603 } 8604 8605 /*@C 8606 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8607 8608 Input Parameter: 8609 . dm - The `DMPLEX` object 8610 8611 Output Parameter: 8612 . cellHeight - The height of a cell 8613 8614 Level: developer 8615 8616 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8617 @*/ 8618 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8619 { 8620 DM_Plex *mesh = (DM_Plex *)dm->data; 8621 8622 PetscFunctionBegin; 8623 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8624 PetscAssertPointer(cellHeight, 2); 8625 *cellHeight = mesh->vtkCellHeight; 8626 PetscFunctionReturn(PETSC_SUCCESS); 8627 } 8628 8629 /*@C 8630 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8631 8632 Input Parameters: 8633 + dm - The `DMPLEX` object 8634 - cellHeight - The height of a cell 8635 8636 Level: developer 8637 8638 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8639 @*/ 8640 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8641 { 8642 DM_Plex *mesh = (DM_Plex *)dm->data; 8643 8644 PetscFunctionBegin; 8645 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8646 mesh->vtkCellHeight = cellHeight; 8647 PetscFunctionReturn(PETSC_SUCCESS); 8648 } 8649 8650 /*@ 8651 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8652 8653 Input Parameters: 8654 + dm - The `DMPLEX` object 8655 - ct - The `DMPolytopeType` of the cell 8656 8657 Output Parameters: 8658 + start - The first cell of this type, or `NULL` 8659 - end - The upper bound on this celltype, or `NULL` 8660 8661 Level: advanced 8662 8663 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8664 @*/ 8665 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8666 { 8667 DM_Plex *mesh = (DM_Plex *)dm->data; 8668 DMLabel label; 8669 PetscInt pStart, pEnd; 8670 8671 PetscFunctionBegin; 8672 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8673 if (start) { 8674 PetscAssertPointer(start, 3); 8675 *start = 0; 8676 } 8677 if (end) { 8678 PetscAssertPointer(end, 4); 8679 *end = 0; 8680 } 8681 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8682 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8683 if (mesh->tr) { 8684 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8685 } else { 8686 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8687 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8688 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8689 } 8690 PetscFunctionReturn(PETSC_SUCCESS); 8691 } 8692 8693 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8694 { 8695 PetscSection section, globalSection; 8696 PetscInt *numbers, p; 8697 8698 PetscFunctionBegin; 8699 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8700 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8701 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8702 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8703 PetscCall(PetscSectionSetUp(section)); 8704 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8705 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8706 for (p = pStart; p < pEnd; ++p) { 8707 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8708 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8709 else numbers[p - pStart] += shift; 8710 } 8711 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8712 if (globalSize) { 8713 PetscLayout layout; 8714 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8715 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8716 PetscCall(PetscLayoutDestroy(&layout)); 8717 } 8718 PetscCall(PetscSectionDestroy(§ion)); 8719 PetscCall(PetscSectionDestroy(&globalSection)); 8720 PetscFunctionReturn(PETSC_SUCCESS); 8721 } 8722 8723 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8724 { 8725 PetscInt cellHeight, cStart, cEnd; 8726 8727 PetscFunctionBegin; 8728 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8729 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8730 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8731 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8732 PetscFunctionReturn(PETSC_SUCCESS); 8733 } 8734 8735 /*@ 8736 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8737 8738 Input Parameter: 8739 . dm - The `DMPLEX` object 8740 8741 Output Parameter: 8742 . globalCellNumbers - Global cell numbers for all cells on this process 8743 8744 Level: developer 8745 8746 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8747 @*/ 8748 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8749 { 8750 DM_Plex *mesh = (DM_Plex *)dm->data; 8751 8752 PetscFunctionBegin; 8753 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8754 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8755 *globalCellNumbers = mesh->globalCellNumbers; 8756 PetscFunctionReturn(PETSC_SUCCESS); 8757 } 8758 8759 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8760 { 8761 PetscInt vStart, vEnd; 8762 8763 PetscFunctionBegin; 8764 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8765 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8766 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8767 PetscFunctionReturn(PETSC_SUCCESS); 8768 } 8769 8770 /*@ 8771 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8772 8773 Input Parameter: 8774 . dm - The `DMPLEX` object 8775 8776 Output Parameter: 8777 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8778 8779 Level: developer 8780 8781 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8782 @*/ 8783 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8784 { 8785 DM_Plex *mesh = (DM_Plex *)dm->data; 8786 8787 PetscFunctionBegin; 8788 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8789 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8790 *globalVertexNumbers = mesh->globalVertexNumbers; 8791 PetscFunctionReturn(PETSC_SUCCESS); 8792 } 8793 8794 /*@ 8795 DMPlexCreatePointNumbering - Create a global numbering for all points. 8796 8797 Collective 8798 8799 Input Parameter: 8800 . dm - The `DMPLEX` object 8801 8802 Output Parameter: 8803 . globalPointNumbers - Global numbers for all points on this process 8804 8805 Level: developer 8806 8807 Notes: 8808 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8809 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8810 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8811 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8812 8813 The partitioned mesh is 8814 ``` 8815 (2)--0--(3)--1--(4) (1)--0--(2) 8816 ``` 8817 and its global numbering is 8818 ``` 8819 (3)--0--(4)--1--(5)--2--(6) 8820 ``` 8821 Then the global numbering is provided as 8822 ``` 8823 [0] Number of indices in set 5 8824 [0] 0 0 8825 [0] 1 1 8826 [0] 2 3 8827 [0] 3 4 8828 [0] 4 -6 8829 [1] Number of indices in set 3 8830 [1] 0 2 8831 [1] 1 5 8832 [1] 2 6 8833 ``` 8834 8835 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8836 @*/ 8837 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8838 { 8839 IS nums[4]; 8840 PetscInt depths[4], gdepths[4], starts[4]; 8841 PetscInt depth, d, shift = 0; 8842 PetscBool empty = PETSC_FALSE; 8843 8844 PetscFunctionBegin; 8845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8846 PetscCall(DMPlexGetDepth(dm, &depth)); 8847 // For unstratified meshes use dim instead of depth 8848 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8849 // If any stratum is empty, we must mark all empty 8850 for (d = 0; d <= depth; ++d) { 8851 PetscInt end; 8852 8853 depths[d] = depth - d; 8854 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8855 if (!(starts[d] - end)) empty = PETSC_TRUE; 8856 } 8857 if (empty) 8858 for (d = 0; d <= depth; ++d) { 8859 depths[d] = -1; 8860 starts[d] = -1; 8861 } 8862 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8863 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8864 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]); 8865 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8866 for (d = 0; d <= depth; ++d) { 8867 PetscInt pStart, pEnd, gsize; 8868 8869 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8870 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8871 shift += gsize; 8872 } 8873 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8874 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8875 PetscFunctionReturn(PETSC_SUCCESS); 8876 } 8877 8878 /*@ 8879 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8880 8881 Input Parameter: 8882 . dm - The `DMPLEX` object 8883 8884 Output Parameter: 8885 . ranks - The rank field 8886 8887 Options Database Key: 8888 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8889 8890 Level: intermediate 8891 8892 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8893 @*/ 8894 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8895 { 8896 DM rdm; 8897 PetscFE fe; 8898 PetscScalar *r; 8899 PetscMPIInt rank; 8900 DMPolytopeType ct; 8901 PetscInt dim, cStart, cEnd, c; 8902 PetscBool simplex; 8903 8904 PetscFunctionBeginUser; 8905 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8906 PetscAssertPointer(ranks, 2); 8907 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8908 PetscCall(DMClone(dm, &rdm)); 8909 PetscCall(DMGetDimension(rdm, &dim)); 8910 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8911 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8912 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8913 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8914 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8915 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8916 PetscCall(PetscFEDestroy(&fe)); 8917 PetscCall(DMCreateDS(rdm)); 8918 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8919 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8920 PetscCall(VecGetArray(*ranks, &r)); 8921 for (c = cStart; c < cEnd; ++c) { 8922 PetscScalar *lr; 8923 8924 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8925 if (lr) *lr = rank; 8926 } 8927 PetscCall(VecRestoreArray(*ranks, &r)); 8928 PetscCall(DMDestroy(&rdm)); 8929 PetscFunctionReturn(PETSC_SUCCESS); 8930 } 8931 8932 /*@ 8933 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8934 8935 Input Parameters: 8936 + dm - The `DMPLEX` 8937 - label - The `DMLabel` 8938 8939 Output Parameter: 8940 . val - The label value field 8941 8942 Options Database Key: 8943 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8944 8945 Level: intermediate 8946 8947 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8948 @*/ 8949 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8950 { 8951 DM rdm, plex; 8952 Vec lval; 8953 PetscSection section; 8954 PetscFE fe; 8955 PetscScalar *v; 8956 PetscInt dim, pStart, pEnd, p, cStart; 8957 DMPolytopeType ct; 8958 char name[PETSC_MAX_PATH_LEN]; 8959 const char *lname, *prefix; 8960 8961 PetscFunctionBeginUser; 8962 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8963 PetscAssertPointer(label, 2); 8964 PetscAssertPointer(val, 3); 8965 PetscCall(DMClone(dm, &rdm)); 8966 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8967 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8968 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8969 PetscCall(DMDestroy(&plex)); 8970 PetscCall(DMGetDimension(rdm, &dim)); 8971 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8972 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8973 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8974 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8975 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8976 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8977 PetscCall(PetscFEDestroy(&fe)); 8978 PetscCall(DMCreateDS(rdm)); 8979 PetscCall(DMCreateGlobalVector(rdm, val)); 8980 PetscCall(DMCreateLocalVector(rdm, &lval)); 8981 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8982 PetscCall(DMGetLocalSection(rdm, §ion)); 8983 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8984 PetscCall(VecGetArray(lval, &v)); 8985 for (p = pStart; p < pEnd; ++p) { 8986 PetscInt cval, dof, off; 8987 8988 PetscCall(PetscSectionGetDof(section, p, &dof)); 8989 if (!dof) continue; 8990 PetscCall(DMLabelGetValue(label, p, &cval)); 8991 PetscCall(PetscSectionGetOffset(section, p, &off)); 8992 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 8993 } 8994 PetscCall(VecRestoreArray(lval, &v)); 8995 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 8996 PetscCall(VecDestroy(&lval)); 8997 PetscCall(DMDestroy(&rdm)); 8998 PetscFunctionReturn(PETSC_SUCCESS); 8999 } 9000 9001 /*@ 9002 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9003 9004 Input Parameter: 9005 . dm - The `DMPLEX` object 9006 9007 Level: developer 9008 9009 Notes: 9010 This is a useful diagnostic when creating meshes programmatically. 9011 9012 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9013 9014 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9015 @*/ 9016 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9017 { 9018 PetscSection coneSection, supportSection; 9019 const PetscInt *cone, *support; 9020 PetscInt coneSize, c, supportSize, s; 9021 PetscInt pStart, pEnd, p, pp, csize, ssize; 9022 PetscBool storagecheck = PETSC_TRUE; 9023 9024 PetscFunctionBegin; 9025 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9026 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9027 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9028 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9029 /* Check that point p is found in the support of its cone points, and vice versa */ 9030 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9031 for (p = pStart; p < pEnd; ++p) { 9032 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9033 PetscCall(DMPlexGetCone(dm, p, &cone)); 9034 for (c = 0; c < coneSize; ++c) { 9035 PetscBool dup = PETSC_FALSE; 9036 PetscInt d; 9037 for (d = c - 1; d >= 0; --d) { 9038 if (cone[c] == cone[d]) { 9039 dup = PETSC_TRUE; 9040 break; 9041 } 9042 } 9043 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9044 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9045 for (s = 0; s < supportSize; ++s) { 9046 if (support[s] == p) break; 9047 } 9048 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9049 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9050 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9051 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9052 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9053 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9054 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9055 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]); 9056 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9057 } 9058 } 9059 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9060 if (p != pp) { 9061 storagecheck = PETSC_FALSE; 9062 continue; 9063 } 9064 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9065 PetscCall(DMPlexGetSupport(dm, p, &support)); 9066 for (s = 0; s < supportSize; ++s) { 9067 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9068 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9069 for (c = 0; c < coneSize; ++c) { 9070 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9071 if (cone[c] != pp) { 9072 c = 0; 9073 break; 9074 } 9075 if (cone[c] == p) break; 9076 } 9077 if (c >= coneSize) { 9078 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9079 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9080 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9081 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9082 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9083 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9084 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9085 } 9086 } 9087 } 9088 if (storagecheck) { 9089 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9090 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9091 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9092 } 9093 PetscFunctionReturn(PETSC_SUCCESS); 9094 } 9095 9096 /* 9097 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. 9098 */ 9099 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9100 { 9101 DMPolytopeType cct; 9102 PetscInt ptpoints[4]; 9103 const PetscInt *cone, *ccone, *ptcone; 9104 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9105 9106 PetscFunctionBegin; 9107 *unsplit = 0; 9108 switch (ct) { 9109 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9110 ptpoints[npt++] = c; 9111 break; 9112 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9113 PetscCall(DMPlexGetCone(dm, c, &cone)); 9114 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9115 for (cp = 0; cp < coneSize; ++cp) { 9116 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9117 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9118 } 9119 break; 9120 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9121 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9122 PetscCall(DMPlexGetCone(dm, c, &cone)); 9123 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9124 for (cp = 0; cp < coneSize; ++cp) { 9125 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9126 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9127 for (ccp = 0; ccp < cconeSize; ++ccp) { 9128 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9129 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9130 PetscInt p; 9131 for (p = 0; p < npt; ++p) 9132 if (ptpoints[p] == ccone[ccp]) break; 9133 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9134 } 9135 } 9136 } 9137 break; 9138 default: 9139 break; 9140 } 9141 for (pt = 0; pt < npt; ++pt) { 9142 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9143 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9144 } 9145 PetscFunctionReturn(PETSC_SUCCESS); 9146 } 9147 9148 /*@ 9149 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9150 9151 Input Parameters: 9152 + dm - The `DMPLEX` object 9153 - cellHeight - Normally 0 9154 9155 Level: developer 9156 9157 Notes: 9158 This is a useful diagnostic when creating meshes programmatically. 9159 Currently applicable only to homogeneous simplex or tensor meshes. 9160 9161 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9162 9163 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9164 @*/ 9165 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9166 { 9167 DMPlexInterpolatedFlag interp; 9168 DMPolytopeType ct; 9169 PetscInt vStart, vEnd, cStart, cEnd, c; 9170 9171 PetscFunctionBegin; 9172 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9173 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9174 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9175 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9176 for (c = cStart; c < cEnd; ++c) { 9177 PetscInt *closure = NULL; 9178 PetscInt coneSize, closureSize, cl, Nv = 0; 9179 9180 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9181 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9182 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9183 if (interp == DMPLEX_INTERPOLATED_FULL) { 9184 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9185 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)); 9186 } 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)) ++Nv; 9191 } 9192 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9193 /* Special Case: Tensor faces with identified vertices */ 9194 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9195 PetscInt unsplit; 9196 9197 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9198 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9199 } 9200 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)); 9201 } 9202 PetscFunctionReturn(PETSC_SUCCESS); 9203 } 9204 9205 /*@ 9206 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9207 9208 Collective 9209 9210 Input Parameters: 9211 + dm - The `DMPLEX` object 9212 - cellHeight - Normally 0 9213 9214 Level: developer 9215 9216 Notes: 9217 This is a useful diagnostic when creating meshes programmatically. 9218 This routine is only relevant for meshes that are fully interpolated across all ranks. 9219 It will error out if a partially interpolated mesh is given on some rank. 9220 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9221 9222 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9223 9224 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9225 @*/ 9226 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9227 { 9228 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9229 DMPlexInterpolatedFlag interpEnum; 9230 9231 PetscFunctionBegin; 9232 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9233 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9234 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9235 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9236 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9237 PetscFunctionReturn(PETSC_SUCCESS); 9238 } 9239 9240 PetscCall(DMGetDimension(dm, &dim)); 9241 PetscCall(DMPlexGetDepth(dm, &depth)); 9242 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9243 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9244 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9245 for (c = cStart; c < cEnd; ++c) { 9246 const PetscInt *cone, *ornt, *faceSizes, *faces; 9247 const DMPolytopeType *faceTypes; 9248 DMPolytopeType ct; 9249 PetscInt numFaces, coneSize, f; 9250 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9251 9252 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9253 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9254 if (unsplit) continue; 9255 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9256 PetscCall(DMPlexGetCone(dm, c, &cone)); 9257 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9258 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9259 for (cl = 0; cl < closureSize * 2; cl += 2) { 9260 const PetscInt p = closure[cl]; 9261 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9262 } 9263 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9264 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); 9265 for (f = 0; f < numFaces; ++f) { 9266 DMPolytopeType fct; 9267 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9268 9269 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9270 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9271 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9272 const PetscInt p = fclosure[cl]; 9273 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9274 } 9275 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]); 9276 for (v = 0; v < fnumCorners; ++v) { 9277 if (fclosure[v] != faces[fOff + v]) { 9278 PetscInt v1; 9279 9280 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9281 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9282 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9283 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9284 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9285 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]); 9286 } 9287 } 9288 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9289 fOff += faceSizes[f]; 9290 } 9291 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9292 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9293 } 9294 } 9295 PetscFunctionReturn(PETSC_SUCCESS); 9296 } 9297 9298 /*@ 9299 DMPlexCheckGeometry - Check the geometry of mesh cells 9300 9301 Input Parameter: 9302 . dm - The `DMPLEX` object 9303 9304 Level: developer 9305 9306 Notes: 9307 This is a useful diagnostic when creating meshes programmatically. 9308 9309 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9310 9311 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9312 @*/ 9313 PetscErrorCode DMPlexCheckGeometry(DM dm) 9314 { 9315 Vec coordinates; 9316 PetscReal detJ, J[9], refVol = 1.0; 9317 PetscReal vol; 9318 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9319 9320 PetscFunctionBegin; 9321 PetscCall(DMGetDimension(dm, &dim)); 9322 PetscCall(DMGetCoordinateDim(dm, &dE)); 9323 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9324 PetscCall(DMPlexGetDepth(dm, &depth)); 9325 for (d = 0; d < dim; ++d) refVol *= 2.0; 9326 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9327 /* Make sure local coordinates are created, because that step is collective */ 9328 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9329 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9330 for (c = cStart; c < cEnd; ++c) { 9331 DMPolytopeType ct; 9332 PetscInt unsplit; 9333 PetscBool ignoreZeroVol = PETSC_FALSE; 9334 9335 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9336 switch (ct) { 9337 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9338 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9339 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9340 ignoreZeroVol = PETSC_TRUE; 9341 break; 9342 default: 9343 break; 9344 } 9345 switch (ct) { 9346 case DM_POLYTOPE_TRI_PRISM: 9347 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9348 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9349 case DM_POLYTOPE_PYRAMID: 9350 continue; 9351 default: 9352 break; 9353 } 9354 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9355 if (unsplit) continue; 9356 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9357 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); 9358 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9359 /* This should work with periodicity since DG coordinates should be used */ 9360 if (depth > 1) { 9361 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9362 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); 9363 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9364 } 9365 } 9366 PetscFunctionReturn(PETSC_SUCCESS); 9367 } 9368 9369 /*@ 9370 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9371 9372 Collective 9373 9374 Input Parameters: 9375 + dm - The `DMPLEX` object 9376 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9377 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9378 9379 Level: developer 9380 9381 Notes: 9382 This is mainly intended for debugging/testing purposes. 9383 9384 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9385 9386 Extra roots can come from periodic cuts, where additional points appear on the boundary 9387 9388 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9389 @*/ 9390 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9391 { 9392 PetscInt l, nleaves, nroots, overlap; 9393 const PetscInt *locals; 9394 const PetscSFNode *remotes; 9395 PetscBool distributed; 9396 MPI_Comm comm; 9397 PetscMPIInt rank; 9398 9399 PetscFunctionBegin; 9400 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9401 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9402 else pointSF = dm->sf; 9403 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9404 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9405 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9406 { 9407 PetscMPIInt mpiFlag; 9408 9409 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9410 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9411 } 9412 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9413 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9414 if (!distributed) { 9415 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); 9416 PetscFunctionReturn(PETSC_SUCCESS); 9417 } 9418 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); 9419 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9420 9421 /* Check SF graph is compatible with DMPlex chart */ 9422 { 9423 PetscInt pStart, pEnd, maxLeaf; 9424 9425 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9426 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9427 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9428 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9429 } 9430 9431 /* Check Point SF has no local points referenced */ 9432 for (l = 0; l < nleaves; l++) { 9433 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); 9434 } 9435 9436 /* Check there are no cells in interface */ 9437 if (!overlap) { 9438 PetscInt cellHeight, cStart, cEnd; 9439 9440 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9441 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9442 for (l = 0; l < nleaves; ++l) { 9443 const PetscInt point = locals ? locals[l] : l; 9444 9445 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9446 } 9447 } 9448 9449 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9450 { 9451 const PetscInt *rootdegree; 9452 9453 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9454 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9455 for (l = 0; l < nleaves; ++l) { 9456 const PetscInt point = locals ? locals[l] : l; 9457 const PetscInt *cone; 9458 PetscInt coneSize, c, idx; 9459 9460 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9461 PetscCall(DMPlexGetCone(dm, point, &cone)); 9462 for (c = 0; c < coneSize; ++c) { 9463 if (!rootdegree[cone[c]]) { 9464 if (locals) { 9465 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9466 } else { 9467 idx = (cone[c] < nleaves) ? cone[c] : -1; 9468 } 9469 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9470 } 9471 } 9472 } 9473 } 9474 PetscFunctionReturn(PETSC_SUCCESS); 9475 } 9476 9477 /*@ 9478 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9479 9480 Input Parameter: 9481 . dm - The `DMPLEX` object 9482 9483 Level: developer 9484 9485 Notes: 9486 This is a useful diagnostic when creating meshes programmatically. 9487 9488 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9489 9490 Currently does not include `DMPlexCheckCellShape()`. 9491 9492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9493 @*/ 9494 PetscErrorCode DMPlexCheck(DM dm) 9495 { 9496 PetscInt cellHeight; 9497 9498 PetscFunctionBegin; 9499 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9500 PetscCall(DMPlexCheckSymmetry(dm)); 9501 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9502 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9503 PetscCall(DMPlexCheckGeometry(dm)); 9504 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9505 PetscCall(DMPlexCheckInterfaceCones(dm)); 9506 PetscFunctionReturn(PETSC_SUCCESS); 9507 } 9508 9509 typedef struct cell_stats { 9510 PetscReal min, max, sum, squaresum; 9511 PetscInt count; 9512 } cell_stats_t; 9513 9514 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9515 { 9516 PetscInt i, N = *len; 9517 9518 for (i = 0; i < N; i++) { 9519 cell_stats_t *A = (cell_stats_t *)a; 9520 cell_stats_t *B = (cell_stats_t *)b; 9521 9522 B->min = PetscMin(A->min, B->min); 9523 B->max = PetscMax(A->max, B->max); 9524 B->sum += A->sum; 9525 B->squaresum += A->squaresum; 9526 B->count += A->count; 9527 } 9528 } 9529 9530 /*@ 9531 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9532 9533 Collective 9534 9535 Input Parameters: 9536 + dm - The `DMPLEX` object 9537 . output - If true, statistics will be displayed on `stdout` 9538 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9539 9540 Level: developer 9541 9542 Notes: 9543 This is mainly intended for debugging/testing purposes. 9544 9545 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9546 9547 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9548 @*/ 9549 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9550 { 9551 DM dmCoarse; 9552 cell_stats_t stats, globalStats; 9553 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9554 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9555 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9556 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9557 PetscMPIInt rank, size; 9558 9559 PetscFunctionBegin; 9560 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9561 stats.min = PETSC_MAX_REAL; 9562 stats.max = PETSC_MIN_REAL; 9563 stats.sum = stats.squaresum = 0.; 9564 stats.count = 0; 9565 9566 PetscCallMPI(MPI_Comm_size(comm, &size)); 9567 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9568 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9569 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9570 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9571 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9572 for (c = cStart; c < cEnd; c++) { 9573 PetscInt i; 9574 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9575 9576 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9577 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9578 for (i = 0; i < PetscSqr(cdim); ++i) { 9579 frobJ += J[i] * J[i]; 9580 frobInvJ += invJ[i] * invJ[i]; 9581 } 9582 cond2 = frobJ * frobInvJ; 9583 cond = PetscSqrtReal(cond2); 9584 9585 stats.min = PetscMin(stats.min, cond); 9586 stats.max = PetscMax(stats.max, cond); 9587 stats.sum += cond; 9588 stats.squaresum += cond2; 9589 stats.count++; 9590 if (output && cond > limit) { 9591 PetscSection coordSection; 9592 Vec coordsLocal; 9593 PetscScalar *coords = NULL; 9594 PetscInt Nv, d, clSize, cl, *closure = NULL; 9595 9596 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9597 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9598 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9599 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9600 for (i = 0; i < Nv / cdim; ++i) { 9601 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9602 for (d = 0; d < cdim; ++d) { 9603 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9604 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9605 } 9606 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9607 } 9608 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9609 for (cl = 0; cl < clSize * 2; cl += 2) { 9610 const PetscInt edge = closure[cl]; 9611 9612 if ((edge >= eStart) && (edge < eEnd)) { 9613 PetscReal len; 9614 9615 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9616 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9617 } 9618 } 9619 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9620 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9621 } 9622 } 9623 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9624 9625 if (size > 1) { 9626 PetscMPIInt blockLengths[2] = {4, 1}; 9627 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9628 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9629 MPI_Op statReduce; 9630 9631 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9632 PetscCallMPI(MPI_Type_commit(&statType)); 9633 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9634 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9635 PetscCallMPI(MPI_Op_free(&statReduce)); 9636 PetscCallMPI(MPI_Type_free(&statType)); 9637 } else { 9638 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9639 } 9640 if (rank == 0) { 9641 count = globalStats.count; 9642 min = globalStats.min; 9643 max = globalStats.max; 9644 mean = globalStats.sum / globalStats.count; 9645 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9646 } 9647 9648 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)); 9649 PetscCall(PetscFree2(J, invJ)); 9650 9651 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9652 if (dmCoarse) { 9653 PetscBool isplex; 9654 9655 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9656 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9657 } 9658 PetscFunctionReturn(PETSC_SUCCESS); 9659 } 9660 9661 /*@ 9662 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9663 orthogonal quality below given tolerance. 9664 9665 Collective 9666 9667 Input Parameters: 9668 + dm - The `DMPLEX` object 9669 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9670 - atol - [0, 1] Absolute tolerance for tagging cells. 9671 9672 Output Parameters: 9673 + OrthQual - `Vec` containing orthogonal quality per cell 9674 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9675 9676 Options Database Keys: 9677 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9678 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9679 9680 Level: intermediate 9681 9682 Notes: 9683 Orthogonal quality is given by the following formula\: 9684 9685 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9686 9687 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 9688 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9689 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9690 calculating the cosine of the angle between these vectors. 9691 9692 Orthogonal quality ranges from 1 (best) to 0 (worst). 9693 9694 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9695 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9696 9697 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9698 9699 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9700 @*/ 9701 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9702 { 9703 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9704 PetscInt *idx; 9705 PetscScalar *oqVals; 9706 const PetscScalar *cellGeomArr, *faceGeomArr; 9707 PetscReal *ci, *fi, *Ai; 9708 MPI_Comm comm; 9709 Vec cellgeom, facegeom; 9710 DM dmFace, dmCell; 9711 IS glob; 9712 ISLocalToGlobalMapping ltog; 9713 PetscViewer vwr; 9714 9715 PetscFunctionBegin; 9716 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9717 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9718 PetscAssertPointer(OrthQual, 4); 9719 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9720 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9721 PetscCall(DMGetDimension(dm, &nc)); 9722 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9723 { 9724 DMPlexInterpolatedFlag interpFlag; 9725 9726 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9727 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9728 PetscMPIInt rank; 9729 9730 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9731 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9732 } 9733 } 9734 if (OrthQualLabel) { 9735 PetscAssertPointer(OrthQualLabel, 5); 9736 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9737 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9738 } else { 9739 *OrthQualLabel = NULL; 9740 } 9741 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9742 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9743 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9744 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9745 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9746 PetscCall(VecCreate(comm, OrthQual)); 9747 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9748 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9749 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9750 PetscCall(VecSetUp(*OrthQual)); 9751 PetscCall(ISDestroy(&glob)); 9752 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9753 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9754 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9755 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9756 PetscCall(VecGetDM(cellgeom, &dmCell)); 9757 PetscCall(VecGetDM(facegeom, &dmFace)); 9758 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9759 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9760 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9761 PetscInt cellarr[2], *adj = NULL; 9762 PetscScalar *cArr, *fArr; 9763 PetscReal minvalc = 1.0, minvalf = 1.0; 9764 PetscFVCellGeom *cg; 9765 9766 idx[cellIter] = cell - cStart; 9767 cellarr[0] = cell; 9768 /* Make indexing into cellGeom easier */ 9769 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9770 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9771 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9772 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9773 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9774 PetscInt i; 9775 const PetscInt neigh = adj[cellneigh]; 9776 PetscReal normci = 0, normfi = 0, normai = 0; 9777 PetscFVCellGeom *cgneigh; 9778 PetscFVFaceGeom *fg; 9779 9780 /* Don't count ourselves in the neighbor list */ 9781 if (neigh == cell) continue; 9782 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9783 cellarr[1] = neigh; 9784 { 9785 PetscInt numcovpts; 9786 const PetscInt *covpts; 9787 9788 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9789 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9790 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9791 } 9792 9793 /* Compute c_i, f_i and their norms */ 9794 for (i = 0; i < nc; i++) { 9795 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9796 fi[i] = fg->centroid[i] - cg->centroid[i]; 9797 Ai[i] = fg->normal[i]; 9798 normci += PetscPowReal(ci[i], 2); 9799 normfi += PetscPowReal(fi[i], 2); 9800 normai += PetscPowReal(Ai[i], 2); 9801 } 9802 normci = PetscSqrtReal(normci); 9803 normfi = PetscSqrtReal(normfi); 9804 normai = PetscSqrtReal(normai); 9805 9806 /* Normalize and compute for each face-cell-normal pair */ 9807 for (i = 0; i < nc; i++) { 9808 ci[i] = ci[i] / normci; 9809 fi[i] = fi[i] / normfi; 9810 Ai[i] = Ai[i] / normai; 9811 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9812 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9813 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9814 } 9815 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9816 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9817 } 9818 PetscCall(PetscFree(adj)); 9819 PetscCall(PetscFree2(cArr, fArr)); 9820 /* Defer to cell if they're equal */ 9821 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9822 if (OrthQualLabel) { 9823 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9824 } 9825 } 9826 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9827 PetscCall(VecAssemblyBegin(*OrthQual)); 9828 PetscCall(VecAssemblyEnd(*OrthQual)); 9829 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9830 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9831 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9832 if (OrthQualLabel) { 9833 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9834 } 9835 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9836 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9837 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9838 PetscFunctionReturn(PETSC_SUCCESS); 9839 } 9840 9841 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9842 * interpolator construction */ 9843 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9844 { 9845 PetscSection section, newSection, gsection; 9846 PetscSF sf; 9847 PetscBool hasConstraints, ghasConstraints; 9848 9849 PetscFunctionBegin; 9850 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9851 PetscAssertPointer(odm, 2); 9852 PetscCall(DMGetLocalSection(dm, §ion)); 9853 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9854 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9855 if (!ghasConstraints) { 9856 PetscCall(PetscObjectReference((PetscObject)dm)); 9857 *odm = dm; 9858 PetscFunctionReturn(PETSC_SUCCESS); 9859 } 9860 PetscCall(DMClone(dm, odm)); 9861 PetscCall(DMCopyFields(dm, *odm)); 9862 PetscCall(DMGetLocalSection(*odm, &newSection)); 9863 PetscCall(DMGetPointSF(*odm, &sf)); 9864 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9865 PetscCall(DMSetGlobalSection(*odm, gsection)); 9866 PetscCall(PetscSectionDestroy(&gsection)); 9867 PetscFunctionReturn(PETSC_SUCCESS); 9868 } 9869 9870 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9871 { 9872 DM dmco, dmfo; 9873 Mat interpo; 9874 Vec rscale; 9875 Vec cglobalo, clocal; 9876 Vec fglobal, fglobalo, flocal; 9877 PetscBool regular; 9878 9879 PetscFunctionBegin; 9880 PetscCall(DMGetFullDM(dmc, &dmco)); 9881 PetscCall(DMGetFullDM(dmf, &dmfo)); 9882 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9883 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9884 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9885 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9886 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9887 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9888 PetscCall(VecSet(cglobalo, 0.)); 9889 PetscCall(VecSet(clocal, 0.)); 9890 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9891 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9892 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9893 PetscCall(VecSet(fglobal, 0.)); 9894 PetscCall(VecSet(fglobalo, 0.)); 9895 PetscCall(VecSet(flocal, 0.)); 9896 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9897 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9898 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9899 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9900 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9901 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9902 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9903 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9904 *shift = fglobal; 9905 PetscCall(VecDestroy(&flocal)); 9906 PetscCall(VecDestroy(&fglobalo)); 9907 PetscCall(VecDestroy(&clocal)); 9908 PetscCall(VecDestroy(&cglobalo)); 9909 PetscCall(VecDestroy(&rscale)); 9910 PetscCall(MatDestroy(&interpo)); 9911 PetscCall(DMDestroy(&dmfo)); 9912 PetscCall(DMDestroy(&dmco)); 9913 PetscFunctionReturn(PETSC_SUCCESS); 9914 } 9915 9916 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9917 { 9918 PetscObject shifto; 9919 Vec shift; 9920 9921 PetscFunctionBegin; 9922 if (!interp) { 9923 Vec rscale; 9924 9925 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9926 PetscCall(VecDestroy(&rscale)); 9927 } else { 9928 PetscCall(PetscObjectReference((PetscObject)interp)); 9929 } 9930 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9931 if (!shifto) { 9932 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9933 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9934 shifto = (PetscObject)shift; 9935 PetscCall(VecDestroy(&shift)); 9936 } 9937 shift = (Vec)shifto; 9938 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9939 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9940 PetscCall(MatDestroy(&interp)); 9941 PetscFunctionReturn(PETSC_SUCCESS); 9942 } 9943 9944 /* Pointwise interpolation 9945 Just code FEM for now 9946 u^f = I u^c 9947 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9948 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9949 I_{ij} = psi^f_i phi^c_j 9950 */ 9951 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9952 { 9953 PetscSection gsc, gsf; 9954 PetscInt m, n; 9955 void *ctx; 9956 DM cdm; 9957 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9958 9959 PetscFunctionBegin; 9960 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9961 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9962 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9963 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9964 9965 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9966 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9967 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9968 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9969 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9970 9971 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9972 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9973 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9974 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9975 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9976 if (scaling) { 9977 /* Use naive scaling */ 9978 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9979 } 9980 PetscFunctionReturn(PETSC_SUCCESS); 9981 } 9982 9983 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9984 { 9985 VecScatter ctx; 9986 9987 PetscFunctionBegin; 9988 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9989 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9990 PetscCall(VecScatterDestroy(&ctx)); 9991 PetscFunctionReturn(PETSC_SUCCESS); 9992 } 9993 9994 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[]) 9995 { 9996 const PetscInt Nc = uOff[1] - uOff[0]; 9997 PetscInt c; 9998 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9999 } 10000 10001 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 10002 { 10003 DM dmc; 10004 PetscDS ds; 10005 Vec ones, locmass; 10006 IS cellIS; 10007 PetscFormKey key; 10008 PetscInt depth; 10009 10010 PetscFunctionBegin; 10011 PetscCall(DMClone(dm, &dmc)); 10012 PetscCall(DMCopyDisc(dm, dmc)); 10013 PetscCall(DMGetDS(dmc, &ds)); 10014 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10015 PetscCall(DMCreateGlobalVector(dmc, mass)); 10016 PetscCall(DMGetLocalVector(dmc, &ones)); 10017 PetscCall(DMGetLocalVector(dmc, &locmass)); 10018 PetscCall(DMPlexGetDepth(dmc, &depth)); 10019 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10020 PetscCall(VecSet(locmass, 0.0)); 10021 PetscCall(VecSet(ones, 1.0)); 10022 key.label = NULL; 10023 key.value = 0; 10024 key.field = 0; 10025 key.part = 0; 10026 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10027 PetscCall(ISDestroy(&cellIS)); 10028 PetscCall(VecSet(*mass, 0.0)); 10029 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 10030 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 10031 PetscCall(DMRestoreLocalVector(dmc, &ones)); 10032 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 10033 PetscCall(DMDestroy(&dmc)); 10034 PetscFunctionReturn(PETSC_SUCCESS); 10035 } 10036 10037 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10038 { 10039 PetscSection gsc, gsf; 10040 PetscInt m, n; 10041 void *ctx; 10042 DM cdm; 10043 PetscBool regular; 10044 10045 PetscFunctionBegin; 10046 if (dmFine == dmCoarse) { 10047 DM dmc; 10048 PetscDS ds; 10049 PetscWeakForm wf; 10050 Vec u; 10051 IS cellIS; 10052 PetscFormKey key; 10053 PetscInt depth; 10054 10055 PetscCall(DMClone(dmFine, &dmc)); 10056 PetscCall(DMCopyDisc(dmFine, dmc)); 10057 PetscCall(DMGetDS(dmc, &ds)); 10058 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10059 PetscCall(PetscWeakFormClear(wf)); 10060 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10061 PetscCall(DMCreateMatrix(dmc, mass)); 10062 PetscCall(DMGetLocalVector(dmc, &u)); 10063 PetscCall(DMPlexGetDepth(dmc, &depth)); 10064 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10065 PetscCall(MatZeroEntries(*mass)); 10066 key.label = NULL; 10067 key.value = 0; 10068 key.field = 0; 10069 key.part = 0; 10070 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10071 PetscCall(ISDestroy(&cellIS)); 10072 PetscCall(DMRestoreLocalVector(dmc, &u)); 10073 PetscCall(DMDestroy(&dmc)); 10074 } else { 10075 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10076 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10077 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10078 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10079 10080 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10081 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10082 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10083 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10084 10085 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10086 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10087 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10088 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10089 } 10090 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10091 PetscFunctionReturn(PETSC_SUCCESS); 10092 } 10093 10094 /*@ 10095 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10096 10097 Input Parameter: 10098 . dm - The `DMPLEX` object 10099 10100 Output Parameter: 10101 . regular - The flag 10102 10103 Level: intermediate 10104 10105 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10106 @*/ 10107 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10108 { 10109 PetscFunctionBegin; 10110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10111 PetscAssertPointer(regular, 2); 10112 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10113 PetscFunctionReturn(PETSC_SUCCESS); 10114 } 10115 10116 /*@ 10117 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10118 10119 Input Parameters: 10120 + dm - The `DMPLEX` object 10121 - regular - The flag 10122 10123 Level: intermediate 10124 10125 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10126 @*/ 10127 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10128 { 10129 PetscFunctionBegin; 10130 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10131 ((DM_Plex *)dm->data)->regularRefinement = regular; 10132 PetscFunctionReturn(PETSC_SUCCESS); 10133 } 10134 10135 /*@ 10136 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10137 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10138 10139 Not Collective 10140 10141 Input Parameter: 10142 . dm - The `DMPLEX` object 10143 10144 Output Parameters: 10145 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10146 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10147 10148 Level: intermediate 10149 10150 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10151 @*/ 10152 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10153 { 10154 DM_Plex *plex = (DM_Plex *)dm->data; 10155 10156 PetscFunctionBegin; 10157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10158 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10159 if (anchorSection) *anchorSection = plex->anchorSection; 10160 if (anchorIS) *anchorIS = plex->anchorIS; 10161 PetscFunctionReturn(PETSC_SUCCESS); 10162 } 10163 10164 /*@ 10165 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10166 10167 Collective 10168 10169 Input Parameters: 10170 + dm - The `DMPLEX` object 10171 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10172 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10173 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10174 10175 Level: intermediate 10176 10177 Notes: 10178 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10179 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10180 combination of other points' degrees of freedom. 10181 10182 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10183 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10184 10185 The reference counts of `anchorSection` and `anchorIS` are incremented. 10186 10187 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10188 @*/ 10189 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10190 { 10191 DM_Plex *plex = (DM_Plex *)dm->data; 10192 PetscMPIInt result; 10193 10194 PetscFunctionBegin; 10195 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10196 if (anchorSection) { 10197 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10198 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10199 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10200 } 10201 if (anchorIS) { 10202 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10203 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10204 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10205 } 10206 10207 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10208 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10209 plex->anchorSection = anchorSection; 10210 10211 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10212 PetscCall(ISDestroy(&plex->anchorIS)); 10213 plex->anchorIS = anchorIS; 10214 10215 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10216 PetscInt size, a, pStart, pEnd; 10217 const PetscInt *anchors; 10218 10219 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10220 PetscCall(ISGetLocalSize(anchorIS, &size)); 10221 PetscCall(ISGetIndices(anchorIS, &anchors)); 10222 for (a = 0; a < size; a++) { 10223 PetscInt p; 10224 10225 p = anchors[a]; 10226 if (p >= pStart && p < pEnd) { 10227 PetscInt dof; 10228 10229 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10230 if (dof) { 10231 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10232 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10233 } 10234 } 10235 } 10236 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10237 } 10238 /* reset the generic constraints */ 10239 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10240 PetscFunctionReturn(PETSC_SUCCESS); 10241 } 10242 10243 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10244 { 10245 PetscSection anchorSection; 10246 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10247 10248 PetscFunctionBegin; 10249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10250 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10251 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10252 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10253 if (numFields) { 10254 PetscInt f; 10255 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10256 10257 for (f = 0; f < numFields; f++) { 10258 PetscInt numComp; 10259 10260 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10261 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10262 } 10263 } 10264 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10265 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10266 pStart = PetscMax(pStart, sStart); 10267 pEnd = PetscMin(pEnd, sEnd); 10268 pEnd = PetscMax(pStart, pEnd); 10269 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10270 for (p = pStart; p < pEnd; p++) { 10271 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10272 if (dof) { 10273 PetscCall(PetscSectionGetDof(section, p, &dof)); 10274 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10275 for (f = 0; f < numFields; f++) { 10276 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10277 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10278 } 10279 } 10280 } 10281 PetscCall(PetscSectionSetUp(*cSec)); 10282 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10283 PetscFunctionReturn(PETSC_SUCCESS); 10284 } 10285 10286 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10287 { 10288 PetscSection aSec; 10289 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10290 const PetscInt *anchors; 10291 PetscInt numFields, f; 10292 IS aIS; 10293 MatType mtype; 10294 PetscBool iscuda, iskokkos; 10295 10296 PetscFunctionBegin; 10297 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10298 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10299 PetscCall(PetscSectionGetStorageSize(section, &n)); 10300 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10301 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10302 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10303 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10304 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10305 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10306 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10307 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10308 else mtype = MATSEQAIJ; 10309 PetscCall(MatSetType(*cMat, mtype)); 10310 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10311 PetscCall(ISGetIndices(aIS, &anchors)); 10312 /* cSec will be a subset of aSec and section */ 10313 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10314 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10315 PetscCall(PetscMalloc1(m + 1, &i)); 10316 i[0] = 0; 10317 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10318 for (p = pStart; p < pEnd; p++) { 10319 PetscInt rDof, rOff, r; 10320 10321 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10322 if (!rDof) continue; 10323 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10324 if (numFields) { 10325 for (f = 0; f < numFields; f++) { 10326 annz = 0; 10327 for (r = 0; r < rDof; r++) { 10328 a = anchors[rOff + r]; 10329 if (a < sStart || a >= sEnd) continue; 10330 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10331 annz += aDof; 10332 } 10333 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10334 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10335 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10336 } 10337 } else { 10338 annz = 0; 10339 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10340 for (q = 0; q < dof; q++) { 10341 a = anchors[rOff + q]; 10342 if (a < sStart || a >= sEnd) continue; 10343 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10344 annz += aDof; 10345 } 10346 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10347 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10348 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10349 } 10350 } 10351 nnz = i[m]; 10352 PetscCall(PetscMalloc1(nnz, &j)); 10353 offset = 0; 10354 for (p = pStart; p < pEnd; p++) { 10355 if (numFields) { 10356 for (f = 0; f < numFields; f++) { 10357 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10358 for (q = 0; q < dof; q++) { 10359 PetscInt rDof, rOff, r; 10360 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10361 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10362 for (r = 0; r < rDof; r++) { 10363 PetscInt s; 10364 10365 a = anchors[rOff + r]; 10366 if (a < sStart || a >= sEnd) continue; 10367 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10368 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10369 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10370 } 10371 } 10372 } 10373 } else { 10374 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10375 for (q = 0; q < dof; q++) { 10376 PetscInt rDof, rOff, r; 10377 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10378 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10379 for (r = 0; r < rDof; r++) { 10380 PetscInt s; 10381 10382 a = anchors[rOff + r]; 10383 if (a < sStart || a >= sEnd) continue; 10384 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10385 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10386 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10387 } 10388 } 10389 } 10390 } 10391 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10392 PetscCall(PetscFree(i)); 10393 PetscCall(PetscFree(j)); 10394 PetscCall(ISRestoreIndices(aIS, &anchors)); 10395 PetscFunctionReturn(PETSC_SUCCESS); 10396 } 10397 10398 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10399 { 10400 DM_Plex *plex = (DM_Plex *)dm->data; 10401 PetscSection anchorSection, section, cSec; 10402 Mat cMat; 10403 10404 PetscFunctionBegin; 10405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10406 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10407 if (anchorSection) { 10408 PetscInt Nf; 10409 10410 PetscCall(DMGetLocalSection(dm, §ion)); 10411 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10412 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10413 PetscCall(DMGetNumFields(dm, &Nf)); 10414 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10415 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10416 PetscCall(PetscSectionDestroy(&cSec)); 10417 PetscCall(MatDestroy(&cMat)); 10418 } 10419 PetscFunctionReturn(PETSC_SUCCESS); 10420 } 10421 10422 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10423 { 10424 IS subis; 10425 PetscSection section, subsection; 10426 10427 PetscFunctionBegin; 10428 PetscCall(DMGetLocalSection(dm, §ion)); 10429 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10430 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10431 /* Create subdomain */ 10432 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10433 /* Create submodel */ 10434 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10435 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10436 PetscCall(DMSetLocalSection(*subdm, subsection)); 10437 PetscCall(PetscSectionDestroy(&subsection)); 10438 PetscCall(DMCopyDisc(dm, *subdm)); 10439 /* Create map from submodel to global model */ 10440 if (is) { 10441 PetscSection sectionGlobal, subsectionGlobal; 10442 IS spIS; 10443 const PetscInt *spmap; 10444 PetscInt *subIndices; 10445 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10446 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10447 10448 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10449 PetscCall(ISGetIndices(spIS, &spmap)); 10450 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10451 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10452 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10453 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10454 for (p = pStart; p < pEnd; ++p) { 10455 PetscInt gdof, pSubSize = 0; 10456 10457 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10458 if (gdof > 0) { 10459 for (f = 0; f < Nf; ++f) { 10460 PetscInt fdof, fcdof; 10461 10462 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10463 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10464 pSubSize += fdof - fcdof; 10465 } 10466 subSize += pSubSize; 10467 if (pSubSize) { 10468 if (bs < 0) { 10469 bs = pSubSize; 10470 } else if (bs != pSubSize) { 10471 /* Layout does not admit a pointwise block size */ 10472 bs = 1; 10473 } 10474 } 10475 } 10476 } 10477 /* Must have same blocksize on all procs (some might have no points) */ 10478 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10479 bsLocal[1] = bs; 10480 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10481 if (bsMinMax[0] != bsMinMax[1]) { 10482 bs = 1; 10483 } else { 10484 bs = bsMinMax[0]; 10485 } 10486 PetscCall(PetscMalloc1(subSize, &subIndices)); 10487 for (p = pStart; p < pEnd; ++p) { 10488 PetscInt gdof, goff; 10489 10490 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10491 if (gdof > 0) { 10492 const PetscInt point = spmap[p]; 10493 10494 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10495 for (f = 0; f < Nf; ++f) { 10496 PetscInt fdof, fcdof, fc, f2, poff = 0; 10497 10498 /* Can get rid of this loop by storing field information in the global section */ 10499 for (f2 = 0; f2 < f; ++f2) { 10500 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10501 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10502 poff += fdof - fcdof; 10503 } 10504 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10505 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10506 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10507 } 10508 } 10509 } 10510 PetscCall(ISRestoreIndices(spIS, &spmap)); 10511 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10512 if (bs > 1) { 10513 /* We need to check that the block size does not come from non-contiguous fields */ 10514 PetscInt i, j, set = 1; 10515 for (i = 0; i < subSize; i += bs) { 10516 for (j = 0; j < bs; ++j) { 10517 if (subIndices[i + j] != subIndices[i] + j) { 10518 set = 0; 10519 break; 10520 } 10521 } 10522 } 10523 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10524 } 10525 /* Attach nullspace */ 10526 for (f = 0; f < Nf; ++f) { 10527 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10528 if ((*subdm)->nullspaceConstructors[f]) break; 10529 } 10530 if (f < Nf) { 10531 MatNullSpace nullSpace; 10532 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10533 10534 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10535 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10536 } 10537 } 10538 PetscFunctionReturn(PETSC_SUCCESS); 10539 } 10540 10541 /*@ 10542 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10543 10544 Input Parameters: 10545 + dm - The `DM` 10546 - dummy - unused argument 10547 10548 Options Database Key: 10549 . -dm_plex_monitor_throughput - Activate the monitor 10550 10551 Level: developer 10552 10553 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10554 @*/ 10555 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10556 { 10557 PetscLogHandler default_handler; 10558 10559 PetscFunctionBegin; 10560 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10561 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10562 if (default_handler) { 10563 PetscLogEvent event; 10564 PetscEventPerfInfo eventInfo; 10565 PetscReal cellRate, flopRate; 10566 PetscInt cStart, cEnd, Nf, N; 10567 const char *name; 10568 10569 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10570 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10571 PetscCall(DMGetNumFields(dm, &Nf)); 10572 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10573 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10574 N = (cEnd - cStart) * Nf * eventInfo.count; 10575 flopRate = eventInfo.flops / eventInfo.time; 10576 cellRate = N / eventInfo.time; 10577 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))); 10578 } else { 10579 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."); 10580 } 10581 PetscFunctionReturn(PETSC_SUCCESS); 10582 } 10583