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