1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 89 90 PetscFunctionBegin; 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 93 PetscCall(ISGetLocalSize(valueIS, &Nct)); 94 PetscCall(ISGetIndices(valueIS, &ctypes)); 95 if (!Nct) cS = cE = 0; 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 } 114 PetscCall(ISDestroy(&valueIS)); 115 // Reset label for fast lookup 116 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 117 if (cStart) *cStart = cS; 118 if (cEnd) *cEnd = cE; 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 123 { 124 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 125 PetscInt *sStart, *sEnd; 126 PetscViewerVTKFieldType *ft; 127 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 128 DMLabel depthLabel, ctLabel; 129 130 PetscFunctionBegin; 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 } 162 163 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 164 *types = 0; 165 166 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 167 if (globalvcdof[c]) ++(*types); 168 } 169 170 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 171 t = 0; 172 if (globalvcdof[DM_NUM_POLYTOPES]) { 173 sStart[t] = vStart; 174 sEnd[t] = vEnd; 175 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 176 ++t; 177 } 178 179 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 180 if (globalvcdof[c]) { 181 const DMPolytopeType ict = (DMPolytopeType)c; 182 183 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 184 sStart[t] = cStart; 185 sEnd[t] = cEnd; 186 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 187 ++t; 188 } 189 } 190 191 if (!*types) { 192 if (field >= 0) { 193 const char *fieldname; 194 195 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 196 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 197 } else { 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 199 } 200 } 201 202 *ssStart = sStart; 203 *ssEnd = sEnd; 204 *sft = ft; 205 PetscFunctionReturn(PETSC_SUCCESS); 206 } 207 208 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 209 { 210 PetscFunctionBegin; 211 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 216 { 217 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 218 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 219 220 PetscFunctionBegin; 221 *ft = PETSC_VTK_INVALID; 222 PetscCall(DMGetCoordinateDim(dm, &cdim)); 223 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 224 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 225 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 226 if (field >= 0) { 227 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 228 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 229 } else { 230 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 231 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 232 } 233 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 234 if (globalvcdof[0]) { 235 *sStart = vStart; 236 *sEnd = vEnd; 237 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 238 else *ft = PETSC_VTK_POINT_FIELD; 239 } else if (globalvcdof[1]) { 240 *sStart = cStart; 241 *sEnd = cEnd; 242 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 243 else *ft = PETSC_VTK_CELL_FIELD; 244 } else { 245 if (field >= 0) { 246 const char *fieldname; 247 248 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 249 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 250 } else { 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 252 } 253 } 254 PetscFunctionReturn(PETSC_SUCCESS); 255 } 256 257 /*@ 258 DMPlexVecView1D - Plot many 1D solutions on the same line graph 259 260 Collective 261 262 Input Parameters: 263 + dm - The `DMPLEX` object 264 . n - The number of vectors 265 . u - The array of local vectors 266 - viewer - The `PetscViewer` 267 268 Level: advanced 269 270 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 271 @*/ 272 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 273 { 274 PetscDS ds; 275 PetscDraw draw = NULL; 276 PetscDrawLG lg; 277 Vec coordinates; 278 const PetscScalar *coords, **sol; 279 PetscReal *vals; 280 PetscInt *Nc; 281 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 282 char **names; 283 284 PetscFunctionBegin; 285 PetscCall(DMGetDS(dm, &ds)); 286 PetscCall(PetscDSGetNumFields(ds, &Nf)); 287 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 288 PetscCall(PetscDSGetComponents(ds, &Nc)); 289 290 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 291 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 292 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 293 294 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 295 for (i = 0, l = 0; i < n; ++i) { 296 const char *vname; 297 298 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 299 for (f = 0; f < Nf; ++f) { 300 PetscObject disc; 301 const char *fname; 302 char tmpname[PETSC_MAX_PATH_LEN]; 303 304 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 305 /* TODO Create names for components */ 306 for (c = 0; c < Nc[f]; ++c, ++l) { 307 PetscCall(PetscObjectGetName(disc, &fname)); 308 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 309 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 311 PetscCall(PetscStrallocpy(tmpname, &names[l])); 312 } 313 } 314 } 315 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 316 /* Just add P_1 support for now */ 317 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 318 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 319 PetscCall(VecGetArrayRead(coordinates, &coords)); 320 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 321 for (v = vStart; v < vEnd; ++v) { 322 PetscScalar *x, *svals; 323 324 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 325 for (i = 0; i < n; ++i) { 326 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 327 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 328 } 329 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 330 } 331 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 332 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 333 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 334 PetscCall(PetscFree3(sol, names, vals)); 335 336 PetscCall(PetscDrawLGDraw(lg)); 337 PetscCall(PetscDrawLGDestroy(&lg)); 338 PetscFunctionReturn(PETSC_SUCCESS); 339 } 340 341 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 342 { 343 DM dm; 344 345 PetscFunctionBegin; 346 PetscCall(VecGetDM(u, &dm)); 347 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 348 PetscFunctionReturn(PETSC_SUCCESS); 349 } 350 351 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 352 { 353 DM dm; 354 PetscSection s; 355 PetscDraw draw, popup; 356 DM cdm; 357 PetscSection coordSection; 358 Vec coordinates; 359 const PetscScalar *array; 360 PetscReal lbound[3], ubound[3]; 361 PetscReal vbound[2], time; 362 PetscBool flg; 363 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 364 const char *name; 365 char title[PETSC_MAX_PATH_LEN]; 366 367 PetscFunctionBegin; 368 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 369 PetscCall(VecGetDM(v, &dm)); 370 PetscCall(DMGetCoordinateDim(dm, &dim)); 371 PetscCall(DMGetLocalSection(dm, &s)); 372 PetscCall(PetscSectionGetNumFields(s, &Nf)); 373 PetscCall(DMGetCoarsenLevel(dm, &level)); 374 PetscCall(DMGetCoordinateDM(dm, &cdm)); 375 PetscCall(DMGetLocalSection(cdm, &coordSection)); 376 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 377 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 378 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 379 380 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 381 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 382 383 PetscCall(VecGetLocalSize(coordinates, &N)); 384 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 385 PetscCall(PetscDrawClear(draw)); 386 387 /* Could implement something like DMDASelectFields() */ 388 for (f = 0; f < Nf; ++f) { 389 DM fdm = dm; 390 Vec fv = v; 391 IS fis; 392 char prefix[PETSC_MAX_PATH_LEN]; 393 const char *fname; 394 395 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 396 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 397 398 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 399 else prefix[0] = '\0'; 400 if (Nf > 1) { 401 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 402 PetscCall(VecGetSubVector(v, fis, &fv)); 403 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 404 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 405 } 406 for (comp = 0; comp < Nc; ++comp, ++w) { 407 PetscInt nmax = 2; 408 409 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 410 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 411 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 412 PetscCall(PetscDrawSetTitle(draw, title)); 413 414 /* TODO Get max and min only for this component */ 415 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 416 if (!flg) { 417 PetscCall(VecMin(fv, NULL, &vbound[0])); 418 PetscCall(VecMax(fv, NULL, &vbound[1])); 419 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 420 } 421 422 PetscCall(PetscDrawGetPopup(draw, &popup)); 423 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 424 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 425 PetscCall(VecGetArrayRead(fv, &array)); 426 for (c = cStart; c < cEnd; ++c) { 427 PetscScalar *coords = NULL, *a = NULL; 428 const PetscScalar *coords_arr; 429 PetscBool isDG; 430 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 431 432 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 433 if (a) { 434 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 435 color[1] = color[2] = color[3] = color[0]; 436 } else { 437 PetscScalar *vals = NULL; 438 PetscInt numVals, va; 439 440 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 441 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 442 switch (numVals / Nc) { 443 case 3: /* P1 Triangle */ 444 case 4: /* P1 Quadrangle */ 445 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 446 break; 447 case 6: /* P2 Triangle */ 448 case 8: /* P2 Quadrangle */ 449 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 450 break; 451 default: 452 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 453 } 454 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 455 } 456 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 457 switch (numCoords) { 458 case 6: 459 case 12: /* Localized triangle */ 460 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 461 break; 462 case 8: 463 case 16: /* Localized quadrilateral */ 464 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 465 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 466 break; 467 default: 468 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 469 } 470 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 471 } 472 PetscCall(VecRestoreArrayRead(fv, &array)); 473 PetscCall(PetscDrawFlush(draw)); 474 PetscCall(PetscDrawPause(draw)); 475 PetscCall(PetscDrawSave(draw)); 476 } 477 if (Nf > 1) { 478 PetscCall(VecRestoreSubVector(v, fis, &fv)); 479 PetscCall(ISDestroy(&fis)); 480 PetscCall(DMDestroy(&fdm)); 481 } 482 } 483 PetscFunctionReturn(PETSC_SUCCESS); 484 } 485 486 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 487 { 488 DM dm; 489 PetscDraw draw; 490 PetscInt dim; 491 PetscBool isnull; 492 493 PetscFunctionBegin; 494 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 495 PetscCall(PetscDrawIsNull(draw, &isnull)); 496 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 497 498 PetscCall(VecGetDM(v, &dm)); 499 PetscCall(DMGetCoordinateDim(dm, &dim)); 500 switch (dim) { 501 case 1: 502 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 503 break; 504 case 2: 505 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 506 break; 507 default: 508 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 509 } 510 PetscFunctionReturn(PETSC_SUCCESS); 511 } 512 513 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 514 { 515 DM dm; 516 Vec locv; 517 const char *name; 518 PetscSection section; 519 PetscInt pStart, pEnd; 520 PetscInt numFields; 521 PetscViewerVTKFieldType ft; 522 523 PetscFunctionBegin; 524 PetscCall(VecGetDM(v, &dm)); 525 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 526 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 527 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 528 PetscCall(VecCopy(v, locv)); 529 PetscCall(DMGetLocalSection(dm, §ion)); 530 PetscCall(PetscSectionGetNumFields(section, &numFields)); 531 if (!numFields) { 532 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 533 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 534 } else { 535 PetscInt f; 536 537 for (f = 0; f < numFields; f++) { 538 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 539 if (ft == PETSC_VTK_INVALID) continue; 540 PetscCall(PetscObjectReference((PetscObject)locv)); 541 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 542 } 543 PetscCall(VecDestroy(&locv)); 544 } 545 PetscFunctionReturn(PETSC_SUCCESS); 546 } 547 548 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 549 { 550 DM dm; 551 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 552 553 PetscFunctionBegin; 554 PetscCall(VecGetDM(v, &dm)); 555 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 561 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 562 PetscInt i, numFields; 563 PetscObject fe; 564 PetscBool fem = PETSC_FALSE; 565 Vec locv = v; 566 const char *name; 567 PetscInt step; 568 PetscReal time; 569 570 PetscCall(DMGetNumFields(dm, &numFields)); 571 for (i = 0; i < numFields; i++) { 572 PetscCall(DMGetField(dm, i, NULL, &fe)); 573 if (fe->classid == PETSCFE_CLASSID) { 574 fem = PETSC_TRUE; 575 break; 576 } 577 } 578 if (fem) { 579 PetscObject isZero; 580 581 PetscCall(DMGetLocalVector(dm, &locv)); 582 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 583 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 584 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 585 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 586 PetscCall(VecCopy(v, locv)); 587 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 588 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 589 } 590 if (isvtk) { 591 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 592 } else if (ishdf5) { 593 #if defined(PETSC_HAVE_HDF5) 594 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 595 #else 596 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 597 #endif 598 } else if (isdraw) { 599 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 600 } else if (isglvis) { 601 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 602 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 603 PetscCall(VecView_GLVis(locv, viewer)); 604 } else if (iscgns) { 605 #if defined(PETSC_HAVE_CGNS) 606 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 607 #else 608 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 609 #endif 610 } 611 if (fem) { 612 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 613 PetscCall(DMRestoreLocalVector(dm, &locv)); 614 } 615 } else { 616 PetscBool isseq; 617 618 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 619 if (isseq) PetscCall(VecView_Seq(v, viewer)); 620 else PetscCall(VecView_MPI(v, viewer)); 621 } 622 PetscFunctionReturn(PETSC_SUCCESS); 623 } 624 625 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 626 { 627 DM dm; 628 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 629 630 PetscFunctionBegin; 631 PetscCall(VecGetDM(v, &dm)); 632 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 633 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 639 if (isvtk || isdraw || isglvis || iscgns) { 640 Vec locv; 641 PetscObject isZero; 642 const char *name; 643 644 PetscCall(DMGetLocalVector(dm, &locv)); 645 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 646 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 647 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 648 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 649 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 650 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 651 PetscCall(VecView_Plex_Local(locv, viewer)); 652 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 653 PetscCall(DMRestoreLocalVector(dm, &locv)); 654 } else if (ishdf5) { 655 #if defined(PETSC_HAVE_HDF5) 656 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 657 #else 658 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 659 #endif 660 } else if (isexodusii) { 661 #if defined(PETSC_HAVE_EXODUSII) 662 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 663 #else 664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 665 #endif 666 } else { 667 PetscBool isseq; 668 669 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 670 if (isseq) PetscCall(VecView_Seq(v, viewer)); 671 else PetscCall(VecView_MPI(v, viewer)); 672 } 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 677 { 678 DM dm; 679 MPI_Comm comm; 680 PetscViewerFormat format; 681 Vec v; 682 PetscBool isvtk, ishdf5; 683 684 PetscFunctionBegin; 685 PetscCall(VecGetDM(originalv, &dm)); 686 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 687 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 688 PetscCall(PetscViewerGetFormat(viewer, &format)); 689 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 691 if (format == PETSC_VIEWER_NATIVE) { 692 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 693 /* this need a better fix */ 694 if (dm->useNatural) { 695 if (dm->sfNatural) { 696 const char *vecname; 697 PetscInt n, nroots; 698 699 PetscCall(VecGetLocalSize(originalv, &n)); 700 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 701 if (n == nroots) { 702 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 703 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 704 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 705 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 706 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 707 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 709 } else v = originalv; 710 } else v = originalv; 711 712 if (ishdf5) { 713 #if defined(PETSC_HAVE_HDF5) 714 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 715 #else 716 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 717 #endif 718 } else if (isvtk) { 719 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 720 } else { 721 PetscBool isseq; 722 723 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 724 if (isseq) PetscCall(VecView_Seq(v, viewer)); 725 else PetscCall(VecView_MPI(v, viewer)); 726 } 727 if (v != originalv) PetscCall(VecDestroy(&v)); 728 PetscFunctionReturn(PETSC_SUCCESS); 729 } 730 731 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 732 { 733 DM dm; 734 PetscBool ishdf5; 735 736 PetscFunctionBegin; 737 PetscCall(VecGetDM(v, &dm)); 738 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 739 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 740 if (ishdf5) { 741 DM dmBC; 742 Vec gv; 743 const char *name; 744 745 PetscCall(DMGetOutputDM(dm, &dmBC)); 746 PetscCall(DMGetGlobalVector(dmBC, &gv)); 747 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 748 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 749 PetscCall(VecLoad_Default(gv, viewer)); 750 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 751 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 753 } else PetscCall(VecLoad_Default(v, viewer)); 754 PetscFunctionReturn(PETSC_SUCCESS); 755 } 756 757 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 758 { 759 DM dm; 760 PetscBool ishdf5, isexodusii; 761 762 PetscFunctionBegin; 763 PetscCall(VecGetDM(v, &dm)); 764 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 765 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 767 if (ishdf5) { 768 #if defined(PETSC_HAVE_HDF5) 769 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 770 #else 771 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 772 #endif 773 } else if (isexodusii) { 774 #if defined(PETSC_HAVE_EXODUSII) 775 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 776 #else 777 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 778 #endif 779 } else PetscCall(VecLoad_Default(v, viewer)); 780 PetscFunctionReturn(PETSC_SUCCESS); 781 } 782 783 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 784 { 785 DM dm; 786 PetscViewerFormat format; 787 PetscBool ishdf5; 788 789 PetscFunctionBegin; 790 PetscCall(VecGetDM(originalv, &dm)); 791 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 792 PetscCall(PetscViewerGetFormat(viewer, &format)); 793 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 794 if (format == PETSC_VIEWER_NATIVE) { 795 if (dm->useNatural) { 796 if (dm->sfNatural) { 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 Vec v; 800 const char *vecname; 801 802 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 803 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 804 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 805 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 806 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 807 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 808 PetscCall(VecDestroy(&v)); 809 #else 810 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 811 #endif 812 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 813 } 814 } else PetscCall(VecLoad_Default(originalv, viewer)); 815 } 816 PetscFunctionReturn(PETSC_SUCCESS); 817 } 818 819 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 820 { 821 PetscSection coordSection; 822 Vec coordinates; 823 DMLabel depthLabel, celltypeLabel; 824 const char *name[4]; 825 const PetscScalar *a; 826 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 827 828 PetscFunctionBegin; 829 PetscCall(DMGetDimension(dm, &dim)); 830 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 831 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 832 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 833 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 834 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 835 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 836 PetscCall(VecGetArrayRead(coordinates, &a)); 837 name[0] = "vertex"; 838 name[1] = "edge"; 839 name[dim - 1] = "face"; 840 name[dim] = "cell"; 841 for (c = cStart; c < cEnd; ++c) { 842 PetscInt *closure = NULL; 843 PetscInt closureSize, cl, ct; 844 845 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 846 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 847 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 848 PetscCall(PetscViewerASCIIPushTab(viewer)); 849 for (cl = 0; cl < closureSize * 2; cl += 2) { 850 PetscInt point = closure[cl], depth, dof, off, d, p; 851 852 if ((point < pStart) || (point >= pEnd)) continue; 853 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 854 if (!dof) continue; 855 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 856 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 858 for (p = 0; p < dof / dim; ++p) { 859 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 860 for (d = 0; d < dim; ++d) { 861 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 862 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 863 } 864 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 865 } 866 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 867 } 868 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 869 PetscCall(PetscViewerASCIIPopTab(viewer)); 870 } 871 PetscCall(VecRestoreArrayRead(coordinates, &a)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 typedef enum { 876 CS_CARTESIAN, 877 CS_POLAR, 878 CS_CYLINDRICAL, 879 CS_SPHERICAL 880 } CoordSystem; 881 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 882 883 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 884 { 885 PetscInt i; 886 887 PetscFunctionBegin; 888 if (dim > 3) { 889 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 890 } else { 891 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 892 893 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 894 switch (cs) { 895 case CS_CARTESIAN: 896 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 897 break; 898 case CS_POLAR: 899 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 900 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 901 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 902 break; 903 case CS_CYLINDRICAL: 904 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 905 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 906 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 907 trcoords[2] = coords[2]; 908 break; 909 case CS_SPHERICAL: 910 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 911 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 912 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 913 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 914 break; 915 } 916 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 917 } 918 PetscFunctionReturn(PETSC_SUCCESS); 919 } 920 921 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 922 { 923 DM_Plex *mesh = (DM_Plex *)dm->data; 924 DM cdm, cdmCell; 925 PetscSection coordSection, coordSectionCell; 926 Vec coordinates, coordinatesCell; 927 PetscViewerFormat format; 928 929 PetscFunctionBegin; 930 PetscCall(PetscViewerGetFormat(viewer, &format)); 931 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 932 const char *name; 933 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 934 PetscInt pStart, pEnd, p, numLabels, l; 935 PetscMPIInt rank, size; 936 937 PetscCall(DMGetCoordinateDM(dm, &cdm)); 938 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 939 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 940 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 941 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 942 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 943 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 944 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 945 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 946 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 947 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 948 PetscCall(DMGetDimension(dm, &dim)); 949 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 950 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 951 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 952 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 953 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 954 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 955 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 956 for (p = pStart; p < pEnd; ++p) { 957 PetscInt dof, off, s; 958 959 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 960 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 961 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 962 } 963 PetscCall(PetscViewerFlush(viewer)); 964 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 965 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 966 for (p = pStart; p < pEnd; ++p) { 967 PetscInt dof, off, c; 968 969 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 970 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 971 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 972 } 973 PetscCall(PetscViewerFlush(viewer)); 974 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 975 if (coordSection && coordinates) { 976 CoordSystem cs = CS_CARTESIAN; 977 const PetscScalar *array, *arrayCell = NULL; 978 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 979 PetscMPIInt rank; 980 const char *name; 981 982 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 983 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 984 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 985 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 986 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 987 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 988 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 989 pStart = PetscMin(pvStart, pcStart); 990 pEnd = PetscMax(pvEnd, pcEnd); 991 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 992 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 994 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 995 996 PetscCall(VecGetArrayRead(coordinates, &array)); 997 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 998 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 999 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1000 for (p = pStart; p < pEnd; ++p) { 1001 PetscInt dof, off; 1002 1003 if (p >= pvStart && p < pvEnd) { 1004 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1005 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1006 if (dof) { 1007 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1008 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1009 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1010 } 1011 } 1012 if (cdmCell && p >= pcStart && p < pcEnd) { 1013 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1014 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1015 if (dof) { 1016 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1017 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1018 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1019 } 1020 } 1021 } 1022 PetscCall(PetscViewerFlush(viewer)); 1023 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1024 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1025 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1026 } 1027 PetscCall(DMGetNumLabels(dm, &numLabels)); 1028 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1029 for (l = 0; l < numLabels; ++l) { 1030 DMLabel label; 1031 PetscBool isdepth; 1032 const char *name; 1033 1034 PetscCall(DMGetLabelName(dm, l, &name)); 1035 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1036 if (isdepth) continue; 1037 PetscCall(DMGetLabel(dm, name, &label)); 1038 PetscCall(DMLabelView(label, viewer)); 1039 } 1040 if (size > 1) { 1041 PetscSF sf; 1042 1043 PetscCall(DMGetPointSF(dm, &sf)); 1044 PetscCall(PetscSFView(sf, viewer)); 1045 } 1046 if (mesh->periodic.face_sfs) 1047 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1048 PetscCall(PetscViewerFlush(viewer)); 1049 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1050 const char *name, *color; 1051 const char *defcolors[3] = {"gray", "orange", "green"}; 1052 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1053 char lname[PETSC_MAX_PATH_LEN]; 1054 PetscReal scale = 2.0; 1055 PetscReal tikzscale = 1.0; 1056 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1057 double tcoords[3]; 1058 PetscScalar *coords; 1059 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1060 PetscMPIInt rank, size; 1061 char **names, **colors, **lcolors; 1062 PetscBool flg, lflg; 1063 PetscBT wp = NULL; 1064 PetscInt pEnd, pStart; 1065 1066 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1069 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1070 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1071 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1072 PetscCall(DMGetDimension(dm, &dim)); 1073 PetscCall(DMPlexGetDepth(dm, &depth)); 1074 PetscCall(DMGetNumLabels(dm, &numLabels)); 1075 numLabels = PetscMax(numLabels, 10); 1076 numColors = 10; 1077 numLColors = 10; 1078 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1080 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1081 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1082 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1083 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1084 n = 4; 1085 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1086 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1087 n = 4; 1088 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1089 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1090 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1091 if (!useLabels) numLabels = 0; 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1093 if (!useColors) { 1094 numColors = 3; 1095 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1096 } 1097 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1098 if (!useColors) { 1099 numLColors = 4; 1100 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1101 } 1102 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1103 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1104 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1105 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1106 if (depth < dim) plotEdges = PETSC_FALSE; 1107 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1108 1109 /* filter points with labelvalue != labeldefaultvalue */ 1110 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1112 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1113 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1114 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1115 if (lflg) { 1116 DMLabel lbl; 1117 1118 PetscCall(DMGetLabel(dm, lname, &lbl)); 1119 if (lbl) { 1120 PetscInt val, defval; 1121 1122 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1123 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1124 for (c = pStart; c < pEnd; c++) { 1125 PetscInt *closure = NULL; 1126 PetscInt closureSize; 1127 1128 PetscCall(DMLabelGetValue(lbl, c, &val)); 1129 if (val == defval) continue; 1130 1131 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1132 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1133 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1134 } 1135 } 1136 } 1137 1138 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1139 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1140 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1141 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1142 \\documentclass[tikz]{standalone}\n\n\ 1143 \\usepackage{pgflibraryshapes}\n\ 1144 \\usetikzlibrary{backgrounds}\n\ 1145 \\usetikzlibrary{arrows}\n\ 1146 \\begin{document}\n")); 1147 if (size > 1) { 1148 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1149 for (p = 0; p < size; ++p) { 1150 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1151 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1152 } 1153 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1154 } 1155 if (drawHasse) { 1156 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1157 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1171 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1172 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1173 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1174 } 1175 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1176 1177 /* Plot vertices */ 1178 PetscCall(VecGetArray(coordinates, &coords)); 1179 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1180 for (v = vStart; v < vEnd; ++v) { 1181 PetscInt off, dof, d; 1182 PetscBool isLabeled = PETSC_FALSE; 1183 1184 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1185 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1186 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1187 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1188 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1189 for (d = 0; d < dof; ++d) { 1190 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1191 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1192 } 1193 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1194 if (dim == 3) { 1195 PetscReal tmp = tcoords[1]; 1196 tcoords[1] = tcoords[2]; 1197 tcoords[2] = -tmp; 1198 } 1199 for (d = 0; d < dof; ++d) { 1200 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1201 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1202 } 1203 if (drawHasse) color = colors[0 % numColors]; 1204 else color = colors[rank % numColors]; 1205 for (l = 0; l < numLabels; ++l) { 1206 PetscInt val; 1207 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1208 if (val >= 0) { 1209 color = lcolors[l % numLColors]; 1210 isLabeled = PETSC_TRUE; 1211 break; 1212 } 1213 } 1214 if (drawNumbers[0]) { 1215 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1216 } else if (drawColors[0]) { 1217 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1218 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1219 } 1220 PetscCall(VecRestoreArray(coordinates, &coords)); 1221 PetscCall(PetscViewerFlush(viewer)); 1222 /* Plot edges */ 1223 if (plotEdges) { 1224 PetscCall(VecGetArray(coordinates, &coords)); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1226 for (e = eStart; e < eEnd; ++e) { 1227 const PetscInt *cone; 1228 PetscInt coneSize, offA, offB, dof, d; 1229 1230 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1231 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1232 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1233 PetscCall(DMPlexGetCone(dm, e, &cone)); 1234 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1235 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1236 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1237 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1238 for (d = 0; d < dof; ++d) { 1239 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1240 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1241 } 1242 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1243 if (dim == 3) { 1244 PetscReal tmp = tcoords[1]; 1245 tcoords[1] = tcoords[2]; 1246 tcoords[2] = -tmp; 1247 } 1248 for (d = 0; d < dof; ++d) { 1249 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1250 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1251 } 1252 if (drawHasse) color = colors[1 % numColors]; 1253 else color = colors[rank % numColors]; 1254 for (l = 0; l < numLabels; ++l) { 1255 PetscInt val; 1256 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1257 if (val >= 0) { 1258 color = lcolors[l % numLColors]; 1259 break; 1260 } 1261 } 1262 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1263 } 1264 PetscCall(VecRestoreArray(coordinates, &coords)); 1265 PetscCall(PetscViewerFlush(viewer)); 1266 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1267 } 1268 /* Plot cells */ 1269 if (dim == 3 || !drawNumbers[1]) { 1270 for (e = eStart; e < eEnd; ++e) { 1271 const PetscInt *cone; 1272 1273 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1274 color = colors[rank % numColors]; 1275 for (l = 0; l < numLabels; ++l) { 1276 PetscInt val; 1277 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1278 if (val >= 0) { 1279 color = lcolors[l % numLColors]; 1280 break; 1281 } 1282 } 1283 PetscCall(DMPlexGetCone(dm, e, &cone)); 1284 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1285 } 1286 } else { 1287 DMPolytopeType ct; 1288 1289 /* Drawing a 2D polygon */ 1290 for (c = cStart; c < cEnd; ++c) { 1291 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1292 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1293 if (DMPolytopeTypeIsHybrid(ct)) { 1294 const PetscInt *cone; 1295 PetscInt coneSize, e; 1296 1297 PetscCall(DMPlexGetCone(dm, c, &cone)); 1298 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1299 for (e = 0; e < coneSize; ++e) { 1300 const PetscInt *econe; 1301 1302 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1303 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)); 1304 } 1305 } else { 1306 PetscInt *closure = NULL; 1307 PetscInt closureSize, Nv = 0, v; 1308 1309 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1310 for (p = 0; p < closureSize * 2; p += 2) { 1311 const PetscInt point = closure[p]; 1312 1313 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1314 } 1315 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1316 for (v = 0; v <= Nv; ++v) { 1317 const PetscInt vertex = closure[v % Nv]; 1318 1319 if (v > 0) { 1320 if (plotEdges) { 1321 const PetscInt *edge; 1322 PetscInt endpoints[2], ne; 1323 1324 endpoints[0] = closure[v - 1]; 1325 endpoints[1] = vertex; 1326 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1327 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1328 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1329 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1330 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1331 } 1332 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1333 } 1334 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1335 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1336 } 1337 } 1338 } 1339 for (c = cStart; c < cEnd; ++c) { 1340 double ccoords[3] = {0.0, 0.0, 0.0}; 1341 PetscBool isLabeled = PETSC_FALSE; 1342 PetscScalar *cellCoords = NULL; 1343 const PetscScalar *array; 1344 PetscInt numCoords, cdim, d; 1345 PetscBool isDG; 1346 1347 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1348 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1349 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1350 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1351 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1352 for (p = 0; p < numCoords / cdim; ++p) { 1353 for (d = 0; d < cdim; ++d) { 1354 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1355 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1356 } 1357 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1358 if (cdim == 3) { 1359 PetscReal tmp = tcoords[1]; 1360 tcoords[1] = tcoords[2]; 1361 tcoords[2] = -tmp; 1362 } 1363 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1364 } 1365 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1366 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1367 for (d = 0; d < cdim; ++d) { 1368 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1369 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1370 } 1371 if (drawHasse) color = colors[depth % numColors]; 1372 else color = colors[rank % numColors]; 1373 for (l = 0; l < numLabels; ++l) { 1374 PetscInt val; 1375 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1376 if (val >= 0) { 1377 color = lcolors[l % numLColors]; 1378 isLabeled = PETSC_TRUE; 1379 break; 1380 } 1381 } 1382 if (drawNumbers[dim]) { 1383 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1384 } else if (drawColors[dim]) { 1385 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1386 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1387 } 1388 if (drawHasse) { 1389 int height = 0; 1390 1391 color = colors[depth % numColors]; 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1397 1398 if (depth > 2) { 1399 color = colors[1 % numColors]; 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1404 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1405 } 1406 1407 color = colors[1 % numColors]; 1408 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1409 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1410 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1411 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1412 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1413 1414 color = colors[0 % numColors]; 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1418 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1419 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1420 1421 for (p = pStart; p < pEnd; ++p) { 1422 const PetscInt *cone; 1423 PetscInt coneSize, cp; 1424 1425 PetscCall(DMPlexGetCone(dm, p, &cone)); 1426 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1427 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1428 } 1429 } 1430 PetscCall(PetscViewerFlush(viewer)); 1431 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1432 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1433 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1434 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1435 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1436 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1437 PetscCall(PetscFree3(names, colors, lcolors)); 1438 PetscCall(PetscBTDestroy(&wp)); 1439 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1440 Vec cown, acown; 1441 VecScatter sct; 1442 ISLocalToGlobalMapping g2l; 1443 IS gid, acis; 1444 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1445 MPI_Group ggroup, ngroup; 1446 PetscScalar *array, nid; 1447 const PetscInt *idxs; 1448 PetscInt *idxs2, *start, *adjacency, *work; 1449 PetscInt64 lm[3], gm[3]; 1450 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1451 PetscMPIInt d1, d2, rank; 1452 1453 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1454 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1455 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1456 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1457 #endif 1458 if (ncomm != MPI_COMM_NULL) { 1459 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1460 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1461 d1 = 0; 1462 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1463 nid = d2; 1464 PetscCallMPI(MPI_Group_free(&ggroup)); 1465 PetscCallMPI(MPI_Group_free(&ngroup)); 1466 PetscCallMPI(MPI_Comm_free(&ncomm)); 1467 } else nid = 0.0; 1468 1469 /* Get connectivity */ 1470 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1471 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1472 1473 /* filter overlapped local cells */ 1474 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1475 PetscCall(ISGetIndices(gid, &idxs)); 1476 PetscCall(ISGetLocalSize(gid, &cum)); 1477 PetscCall(PetscMalloc1(cum, &idxs2)); 1478 for (c = cStart, cum = 0; c < cEnd; c++) { 1479 if (idxs[c - cStart] < 0) continue; 1480 idxs2[cum++] = idxs[c - cStart]; 1481 } 1482 PetscCall(ISRestoreIndices(gid, &idxs)); 1483 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1484 PetscCall(ISDestroy(&gid)); 1485 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1486 1487 /* support for node-aware cell locality */ 1488 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1489 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1490 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1491 PetscCall(VecGetArray(cown, &array)); 1492 for (c = 0; c < numVertices; c++) array[c] = nid; 1493 PetscCall(VecRestoreArray(cown, &array)); 1494 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1495 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1496 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1497 PetscCall(ISDestroy(&acis)); 1498 PetscCall(VecScatterDestroy(&sct)); 1499 PetscCall(VecDestroy(&cown)); 1500 1501 /* compute edgeCut */ 1502 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1503 PetscCall(PetscMalloc1(cum, &work)); 1504 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1505 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1506 PetscCall(ISDestroy(&gid)); 1507 PetscCall(VecGetArray(acown, &array)); 1508 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1509 PetscInt totl; 1510 1511 totl = start[c + 1] - start[c]; 1512 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1513 for (i = 0; i < totl; i++) { 1514 if (work[i] < 0) { 1515 ect += 1; 1516 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1517 } 1518 } 1519 } 1520 PetscCall(PetscFree(work)); 1521 PetscCall(VecRestoreArray(acown, &array)); 1522 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1523 lm[1] = -numVertices; 1524 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1526 lm[0] = ect; /* edgeCut */ 1527 lm[1] = ectn; /* node-aware edgeCut */ 1528 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1529 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1530 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1531 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1532 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1533 #else 1534 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1535 #endif 1536 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1537 PetscCall(PetscFree(start)); 1538 PetscCall(PetscFree(adjacency)); 1539 PetscCall(VecDestroy(&acown)); 1540 } else { 1541 const char *name; 1542 PetscInt *sizes, *hybsizes, *ghostsizes; 1543 PetscInt locDepth, depth, cellHeight, dim, d; 1544 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1545 PetscInt numLabels, l, maxSize = 17; 1546 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1547 MPI_Comm comm; 1548 PetscMPIInt size, rank; 1549 1550 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1551 PetscCallMPI(MPI_Comm_size(comm, &size)); 1552 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1553 PetscCall(DMGetDimension(dm, &dim)); 1554 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1555 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1556 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1557 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1558 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1559 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1560 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1561 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1562 gcNum = gcEnd - gcStart; 1563 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1564 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1565 for (d = 0; d <= depth; d++) { 1566 PetscInt Nc[2] = {0, 0}, ict; 1567 1568 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1569 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1570 ict = ct0; 1571 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1572 ct0 = (DMPolytopeType)ict; 1573 for (p = pStart; p < pEnd; ++p) { 1574 DMPolytopeType ct; 1575 1576 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1577 if (ct == ct0) ++Nc[0]; 1578 else ++Nc[1]; 1579 } 1580 if (size < maxSize) { 1581 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1582 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1583 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1584 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1585 for (p = 0; p < size; ++p) { 1586 if (rank == 0) { 1587 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1588 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1589 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1590 } 1591 } 1592 } else { 1593 PetscInt locMinMax[2]; 1594 1595 locMinMax[0] = Nc[0] + Nc[1]; 1596 locMinMax[1] = Nc[0] + Nc[1]; 1597 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1598 locMinMax[0] = Nc[1]; 1599 locMinMax[1] = Nc[1]; 1600 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1601 if (d == depth) { 1602 locMinMax[0] = gcNum; 1603 locMinMax[1] = gcNum; 1604 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1605 } 1606 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1607 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1608 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1609 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1610 } 1611 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1612 } 1613 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1614 { 1615 const PetscReal *maxCell; 1616 const PetscReal *L; 1617 PetscBool localized; 1618 1619 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1620 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1621 if (L || localized) { 1622 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1623 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1624 if (L) { 1625 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1626 for (d = 0; d < dim; ++d) { 1627 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1628 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1629 } 1630 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1631 } 1632 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1633 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1634 } 1635 } 1636 PetscCall(DMGetNumLabels(dm, &numLabels)); 1637 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1638 for (l = 0; l < numLabels; ++l) { 1639 DMLabel label; 1640 const char *name; 1641 IS valueIS; 1642 const PetscInt *values; 1643 PetscInt numValues, v; 1644 1645 PetscCall(DMGetLabelName(dm, l, &name)); 1646 PetscCall(DMGetLabel(dm, name, &label)); 1647 PetscCall(DMLabelGetNumValues(label, &numValues)); 1648 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1649 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1650 PetscCall(ISGetIndices(valueIS, &values)); 1651 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1652 for (v = 0; v < numValues; ++v) { 1653 PetscInt size; 1654 1655 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1656 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1657 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1658 } 1659 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1660 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1661 PetscCall(ISRestoreIndices(valueIS, &values)); 1662 PetscCall(ISDestroy(&valueIS)); 1663 } 1664 { 1665 char **labelNames; 1666 PetscInt Nl = numLabels; 1667 PetscBool flg; 1668 1669 PetscCall(PetscMalloc1(Nl, &labelNames)); 1670 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1671 for (l = 0; l < Nl; ++l) { 1672 DMLabel label; 1673 1674 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1675 if (flg) { 1676 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1677 PetscCall(DMLabelView(label, viewer)); 1678 } 1679 PetscCall(PetscFree(labelNames[l])); 1680 } 1681 PetscCall(PetscFree(labelNames)); 1682 } 1683 /* If no fields are specified, people do not want to see adjacency */ 1684 if (dm->Nf) { 1685 PetscInt f; 1686 1687 for (f = 0; f < dm->Nf; ++f) { 1688 const char *name; 1689 1690 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1691 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1692 PetscCall(PetscViewerASCIIPushTab(viewer)); 1693 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1694 if (dm->fields[f].adjacency[0]) { 1695 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1696 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1697 } else { 1698 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1699 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1700 } 1701 PetscCall(PetscViewerASCIIPopTab(viewer)); 1702 } 1703 } 1704 PetscCall(DMGetCoarseDM(dm, &cdm)); 1705 if (cdm) { 1706 PetscCall(PetscViewerASCIIPushTab(viewer)); 1707 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1708 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1709 PetscCall(PetscViewerASCIIPopTab(viewer)); 1710 } 1711 } 1712 PetscFunctionReturn(PETSC_SUCCESS); 1713 } 1714 1715 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1716 { 1717 DMPolytopeType ct; 1718 PetscMPIInt rank; 1719 PetscInt cdim; 1720 1721 PetscFunctionBegin; 1722 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1723 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1724 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1725 switch (ct) { 1726 case DM_POLYTOPE_SEGMENT: 1727 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1728 switch (cdim) { 1729 case 1: { 1730 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1731 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1732 1733 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1734 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1735 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1736 } break; 1737 case 2: { 1738 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1739 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1740 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1741 1742 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1744 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)); 1745 } break; 1746 default: 1747 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1748 } 1749 break; 1750 case DM_POLYTOPE_TRIANGLE: 1751 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)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1754 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1755 break; 1756 case DM_POLYTOPE_QUADRILATERAL: 1757 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)); 1758 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)); 1759 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1760 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1761 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1762 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1763 break; 1764 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1765 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)); 1766 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)); 1767 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1768 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1769 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1770 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1771 break; 1772 case DM_POLYTOPE_FV_GHOST: 1773 break; 1774 default: 1775 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1776 } 1777 PetscFunctionReturn(PETSC_SUCCESS); 1778 } 1779 1780 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1781 { 1782 PetscReal centroid[2] = {0., 0.}; 1783 PetscMPIInt rank; 1784 PetscInt fillColor; 1785 1786 PetscFunctionBegin; 1787 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1788 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1789 for (PetscInt v = 0; v < Nv; ++v) { 1790 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1791 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1792 } 1793 for (PetscInt e = 0; e < Nv; ++e) { 1794 refCoords[0] = refVertices[e * 2 + 0]; 1795 refCoords[1] = refVertices[e * 2 + 1]; 1796 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1797 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1798 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1799 } 1800 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1801 for (PetscInt d = 0; d < edgeDiv; ++d) { 1802 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)); 1803 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1804 } 1805 } 1806 PetscFunctionReturn(PETSC_SUCCESS); 1807 } 1808 1809 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1810 { 1811 DMPolytopeType ct; 1812 1813 PetscFunctionBegin; 1814 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1815 switch (ct) { 1816 case DM_POLYTOPE_TRIANGLE: { 1817 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1818 1819 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1820 } break; 1821 case DM_POLYTOPE_QUADRILATERAL: { 1822 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1823 1824 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1825 } break; 1826 default: 1827 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1828 } 1829 PetscFunctionReturn(PETSC_SUCCESS); 1830 } 1831 1832 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1833 { 1834 PetscDraw draw; 1835 DM cdm; 1836 PetscSection coordSection; 1837 Vec coordinates; 1838 PetscReal xyl[3], xyr[3]; 1839 PetscReal *refCoords, *edgeCoords; 1840 PetscBool isnull, drawAffine; 1841 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1842 1843 PetscFunctionBegin; 1844 PetscCall(DMGetCoordinateDim(dm, &dim)); 1845 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1846 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1847 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1848 edgeDiv = cDegree + 1; 1849 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1850 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1851 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1852 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1853 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1854 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1855 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1856 1857 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1858 PetscCall(PetscDrawIsNull(draw, &isnull)); 1859 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1860 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1861 1862 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1863 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1864 PetscCall(PetscDrawClear(draw)); 1865 1866 for (c = cStart; c < cEnd; ++c) { 1867 PetscScalar *coords = NULL; 1868 const PetscScalar *coords_arr; 1869 PetscInt numCoords; 1870 PetscBool isDG; 1871 1872 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1873 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1874 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1875 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1876 } 1877 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1878 PetscCall(PetscDrawFlush(draw)); 1879 PetscCall(PetscDrawPause(draw)); 1880 PetscCall(PetscDrawSave(draw)); 1881 PetscFunctionReturn(PETSC_SUCCESS); 1882 } 1883 1884 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1885 { 1886 DM odm = dm, rdm = dm, cdm; 1887 PetscFE fe; 1888 PetscSpace sp; 1889 PetscClassId id; 1890 PetscInt degree; 1891 PetscBool hoView = PETSC_TRUE; 1892 1893 PetscFunctionBegin; 1894 PetscObjectOptionsBegin((PetscObject)dm); 1895 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1896 PetscOptionsEnd(); 1897 PetscCall(PetscObjectReference((PetscObject)dm)); 1898 *hdm = dm; 1899 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1900 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1901 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1902 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1903 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1904 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1905 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1906 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1907 DM cdm, rcdm; 1908 Mat In; 1909 Vec cl, rcl; 1910 1911 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1912 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1913 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1914 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1915 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1916 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1917 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1918 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1919 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1920 PetscCall(MatMult(In, cl, rcl)); 1921 PetscCall(MatDestroy(&In)); 1922 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1923 PetscCall(DMDestroy(&odm)); 1924 odm = rdm; 1925 } 1926 *hdm = rdm; 1927 PetscFunctionReturn(PETSC_SUCCESS); 1928 } 1929 1930 #if defined(PETSC_HAVE_EXODUSII) 1931 #include <exodusII.h> 1932 #include <petscviewerexodusii.h> 1933 #endif 1934 1935 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1936 { 1937 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1938 char name[PETSC_MAX_PATH_LEN]; 1939 1940 PetscFunctionBegin; 1941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1942 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1943 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1944 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1945 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1946 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1947 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1948 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1949 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1950 if (iascii) { 1951 PetscViewerFormat format; 1952 PetscCall(PetscViewerGetFormat(viewer, &format)); 1953 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1954 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1955 } else if (ishdf5) { 1956 #if defined(PETSC_HAVE_HDF5) 1957 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1958 #else 1959 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1960 #endif 1961 } else if (isvtk) { 1962 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1963 } else if (isdraw) { 1964 DM hdm; 1965 1966 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1967 PetscCall(DMPlexView_Draw(hdm, viewer)); 1968 PetscCall(DMDestroy(&hdm)); 1969 } else if (isglvis) { 1970 PetscCall(DMPlexView_GLVis(dm, viewer)); 1971 #if defined(PETSC_HAVE_EXODUSII) 1972 } else if (isexodus) { 1973 /* 1974 exodusII requires that all sets be part of exactly one cell set. 1975 If the dm does not have a "Cell Sets" label defined, we create one 1976 with ID 1, containing all cells. 1977 Note that if the Cell Sets label is defined but does not cover all cells, 1978 we may still have a problem. This should probably be checked here or in the viewer; 1979 */ 1980 PetscInt numCS; 1981 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1982 if (!numCS) { 1983 PetscInt cStart, cEnd, c; 1984 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1985 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1986 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1987 } 1988 PetscCall(DMView_PlexExodusII(dm, viewer)); 1989 #endif 1990 #if defined(PETSC_HAVE_CGNS) 1991 } else if (iscgns) { 1992 PetscCall(DMView_PlexCGNS(dm, viewer)); 1993 #endif 1994 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1995 /* Optionally view the partition */ 1996 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1997 if (flg) { 1998 Vec ranks; 1999 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2000 PetscCall(VecView(ranks, viewer)); 2001 PetscCall(VecDestroy(&ranks)); 2002 } 2003 /* Optionally view a label */ 2004 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2005 if (flg) { 2006 DMLabel label; 2007 Vec val; 2008 2009 PetscCall(DMGetLabel(dm, name, &label)); 2010 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2011 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2012 PetscCall(VecView(val, viewer)); 2013 PetscCall(VecDestroy(&val)); 2014 } 2015 PetscFunctionReturn(PETSC_SUCCESS); 2016 } 2017 2018 /*@ 2019 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2020 2021 Collective 2022 2023 Input Parameters: 2024 + dm - The `DM` whose topology is to be saved 2025 - viewer - The `PetscViewer` to save it in 2026 2027 Level: advanced 2028 2029 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2030 @*/ 2031 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2032 { 2033 PetscBool ishdf5; 2034 2035 PetscFunctionBegin; 2036 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2037 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2038 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2039 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2040 if (ishdf5) { 2041 #if defined(PETSC_HAVE_HDF5) 2042 PetscViewerFormat format; 2043 PetscCall(PetscViewerGetFormat(viewer, &format)); 2044 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2045 IS globalPointNumbering; 2046 2047 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2048 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2049 PetscCall(ISDestroy(&globalPointNumbering)); 2050 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2051 #else 2052 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2053 #endif 2054 } 2055 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2056 PetscFunctionReturn(PETSC_SUCCESS); 2057 } 2058 2059 /*@ 2060 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2061 2062 Collective 2063 2064 Input Parameters: 2065 + dm - The `DM` whose coordinates are to be saved 2066 - viewer - The `PetscViewer` for saving 2067 2068 Level: advanced 2069 2070 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2071 @*/ 2072 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2073 { 2074 PetscBool ishdf5; 2075 2076 PetscFunctionBegin; 2077 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2078 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2079 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2080 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2081 if (ishdf5) { 2082 #if defined(PETSC_HAVE_HDF5) 2083 PetscViewerFormat format; 2084 PetscCall(PetscViewerGetFormat(viewer, &format)); 2085 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2086 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2087 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2088 #else 2089 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2090 #endif 2091 } 2092 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2093 PetscFunctionReturn(PETSC_SUCCESS); 2094 } 2095 2096 /*@ 2097 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2098 2099 Collective 2100 2101 Input Parameters: 2102 + dm - The `DM` whose labels are to be saved 2103 - viewer - The `PetscViewer` for saving 2104 2105 Level: advanced 2106 2107 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2108 @*/ 2109 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2110 { 2111 PetscBool ishdf5; 2112 2113 PetscFunctionBegin; 2114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2115 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2116 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2117 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2118 if (ishdf5) { 2119 #if defined(PETSC_HAVE_HDF5) 2120 IS globalPointNumbering; 2121 PetscViewerFormat format; 2122 2123 PetscCall(PetscViewerGetFormat(viewer, &format)); 2124 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2125 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2126 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2127 PetscCall(ISDestroy(&globalPointNumbering)); 2128 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2129 #else 2130 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2131 #endif 2132 } 2133 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2134 PetscFunctionReturn(PETSC_SUCCESS); 2135 } 2136 2137 /*@ 2138 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2139 2140 Collective 2141 2142 Input Parameters: 2143 + dm - The `DM` that contains the topology on which the section to be saved is defined 2144 . viewer - The `PetscViewer` for saving 2145 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2146 2147 Level: advanced 2148 2149 Notes: 2150 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. 2151 2152 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. 2153 2154 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2155 @*/ 2156 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2157 { 2158 PetscBool ishdf5; 2159 2160 PetscFunctionBegin; 2161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2162 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2163 if (!sectiondm) sectiondm = dm; 2164 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2165 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2166 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2167 if (ishdf5) { 2168 #if defined(PETSC_HAVE_HDF5) 2169 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2170 #else 2171 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2172 #endif 2173 } 2174 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2175 PetscFunctionReturn(PETSC_SUCCESS); 2176 } 2177 2178 /*@ 2179 DMPlexGlobalVectorView - Saves a global vector 2180 2181 Collective 2182 2183 Input Parameters: 2184 + dm - The `DM` that represents the topology 2185 . viewer - The `PetscViewer` to save data with 2186 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2187 - vec - The global vector to be saved 2188 2189 Level: advanced 2190 2191 Notes: 2192 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. 2193 2194 Calling sequence: 2195 .vb 2196 DMCreate(PETSC_COMM_WORLD, &dm); 2197 DMSetType(dm, DMPLEX); 2198 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2199 DMClone(dm, §iondm); 2200 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2201 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2202 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2203 PetscSectionSetChart(section, pStart, pEnd); 2204 PetscSectionSetUp(section); 2205 DMSetLocalSection(sectiondm, section); 2206 PetscSectionDestroy(§ion); 2207 DMGetGlobalVector(sectiondm, &vec); 2208 PetscObjectSetName((PetscObject)vec, "vec_name"); 2209 DMPlexTopologyView(dm, viewer); 2210 DMPlexSectionView(dm, viewer, sectiondm); 2211 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2212 DMRestoreGlobalVector(sectiondm, &vec); 2213 DMDestroy(§iondm); 2214 DMDestroy(&dm); 2215 .ve 2216 2217 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2218 @*/ 2219 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2220 { 2221 PetscBool ishdf5; 2222 2223 PetscFunctionBegin; 2224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2225 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2226 if (!sectiondm) sectiondm = dm; 2227 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2228 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2229 /* Check consistency */ 2230 { 2231 PetscSection section; 2232 PetscBool includesConstraints; 2233 PetscInt m, m1; 2234 2235 PetscCall(VecGetLocalSize(vec, &m1)); 2236 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2237 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2238 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2239 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2240 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2241 } 2242 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2243 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2244 if (ishdf5) { 2245 #if defined(PETSC_HAVE_HDF5) 2246 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2247 #else 2248 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2249 #endif 2250 } 2251 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2252 PetscFunctionReturn(PETSC_SUCCESS); 2253 } 2254 2255 /*@ 2256 DMPlexLocalVectorView - Saves a local vector 2257 2258 Collective 2259 2260 Input Parameters: 2261 + dm - The `DM` that represents the topology 2262 . viewer - The `PetscViewer` to save data with 2263 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2264 - vec - The local vector to be saved 2265 2266 Level: advanced 2267 2268 Note: 2269 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. 2270 2271 Calling sequence: 2272 .vb 2273 DMCreate(PETSC_COMM_WORLD, &dm); 2274 DMSetType(dm, DMPLEX); 2275 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2276 DMClone(dm, §iondm); 2277 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2278 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2279 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2280 PetscSectionSetChart(section, pStart, pEnd); 2281 PetscSectionSetUp(section); 2282 DMSetLocalSection(sectiondm, section); 2283 DMGetLocalVector(sectiondm, &vec); 2284 PetscObjectSetName((PetscObject)vec, "vec_name"); 2285 DMPlexTopologyView(dm, viewer); 2286 DMPlexSectionView(dm, viewer, sectiondm); 2287 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2288 DMRestoreLocalVector(sectiondm, &vec); 2289 DMDestroy(§iondm); 2290 DMDestroy(&dm); 2291 .ve 2292 2293 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2294 @*/ 2295 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2296 { 2297 PetscBool ishdf5; 2298 2299 PetscFunctionBegin; 2300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2301 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2302 if (!sectiondm) sectiondm = dm; 2303 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2304 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2305 /* Check consistency */ 2306 { 2307 PetscSection section; 2308 PetscBool includesConstraints; 2309 PetscInt m, m1; 2310 2311 PetscCall(VecGetLocalSize(vec, &m1)); 2312 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2313 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2314 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2315 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2316 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2317 } 2318 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2319 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2320 if (ishdf5) { 2321 #if defined(PETSC_HAVE_HDF5) 2322 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2323 #else 2324 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2325 #endif 2326 } 2327 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2328 PetscFunctionReturn(PETSC_SUCCESS); 2329 } 2330 2331 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2332 { 2333 PetscBool ishdf5; 2334 2335 PetscFunctionBegin; 2336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2337 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2338 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2339 if (ishdf5) { 2340 #if defined(PETSC_HAVE_HDF5) 2341 PetscViewerFormat format; 2342 PetscCall(PetscViewerGetFormat(viewer, &format)); 2343 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2344 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2345 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2346 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2347 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2348 PetscFunctionReturn(PETSC_SUCCESS); 2349 #else 2350 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2351 #endif 2352 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2353 } 2354 2355 /*@ 2356 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2357 2358 Collective 2359 2360 Input Parameters: 2361 + dm - The `DM` into which the topology is loaded 2362 - viewer - The `PetscViewer` for the saved topology 2363 2364 Output Parameter: 2365 . 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 2366 2367 Level: advanced 2368 2369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2370 `PetscViewer`, `PetscSF` 2371 @*/ 2372 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2373 { 2374 PetscBool ishdf5; 2375 2376 PetscFunctionBegin; 2377 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2378 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2379 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2380 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2381 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2382 if (ishdf5) { 2383 #if defined(PETSC_HAVE_HDF5) 2384 PetscViewerFormat format; 2385 PetscCall(PetscViewerGetFormat(viewer, &format)); 2386 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2387 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2388 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2389 #else 2390 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2391 #endif 2392 } 2393 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2394 PetscFunctionReturn(PETSC_SUCCESS); 2395 } 2396 2397 /*@ 2398 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2399 2400 Collective 2401 2402 Input Parameters: 2403 + dm - The `DM` into which the coordinates are loaded 2404 . viewer - The `PetscViewer` for the saved coordinates 2405 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2406 2407 Level: advanced 2408 2409 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2410 `PetscSF`, `PetscViewer` 2411 @*/ 2412 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2413 { 2414 PetscBool ishdf5; 2415 2416 PetscFunctionBegin; 2417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2418 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2419 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2420 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2421 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2422 if (ishdf5) { 2423 #if defined(PETSC_HAVE_HDF5) 2424 PetscViewerFormat format; 2425 PetscCall(PetscViewerGetFormat(viewer, &format)); 2426 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2427 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2428 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2429 #else 2430 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2431 #endif 2432 } 2433 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2434 PetscFunctionReturn(PETSC_SUCCESS); 2435 } 2436 2437 /*@ 2438 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2439 2440 Collective 2441 2442 Input Parameters: 2443 + dm - The `DM` into which the labels are loaded 2444 . viewer - The `PetscViewer` for the saved labels 2445 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2446 2447 Level: advanced 2448 2449 Note: 2450 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2451 2452 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2453 `PetscSF`, `PetscViewer` 2454 @*/ 2455 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2456 { 2457 PetscBool ishdf5; 2458 2459 PetscFunctionBegin; 2460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2461 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2462 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2463 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2464 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2465 if (ishdf5) { 2466 #if defined(PETSC_HAVE_HDF5) 2467 PetscViewerFormat format; 2468 2469 PetscCall(PetscViewerGetFormat(viewer, &format)); 2470 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2471 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2472 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2473 #else 2474 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2475 #endif 2476 } 2477 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2478 PetscFunctionReturn(PETSC_SUCCESS); 2479 } 2480 2481 /*@ 2482 DMPlexSectionLoad - Loads section into a `DMPLEX` 2483 2484 Collective 2485 2486 Input Parameters: 2487 + dm - The `DM` that represents the topology 2488 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2489 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2490 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2491 2492 Output Parameters: 2493 + 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) 2494 - 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) 2495 2496 Level: advanced 2497 2498 Notes: 2499 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. 2500 2501 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. 2502 2503 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. 2504 2505 Example using 2 processes: 2506 .vb 2507 NX (number of points on dm): 4 2508 sectionA : the on-disk section 2509 vecA : a vector associated with sectionA 2510 sectionB : sectiondm's local section constructed in this function 2511 vecB (local) : a vector associated with sectiondm's local section 2512 vecB (global) : a vector associated with sectiondm's global section 2513 2514 rank 0 rank 1 2515 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2516 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2517 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2518 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2519 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2520 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2521 sectionB->atlasDof : 1 0 1 | 1 3 2522 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2523 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2524 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2525 .ve 2526 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2527 2528 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2529 @*/ 2530 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2531 { 2532 PetscBool ishdf5; 2533 2534 PetscFunctionBegin; 2535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2536 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2537 if (!sectiondm) sectiondm = dm; 2538 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2539 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2540 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2541 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2542 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2543 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2544 if (ishdf5) { 2545 #if defined(PETSC_HAVE_HDF5) 2546 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2547 #else 2548 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2549 #endif 2550 } 2551 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2552 PetscFunctionReturn(PETSC_SUCCESS); 2553 } 2554 2555 /*@ 2556 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2557 2558 Collective 2559 2560 Input Parameters: 2561 + dm - The `DM` that represents the topology 2562 . viewer - The `PetscViewer` that represents the on-disk vector data 2563 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2564 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2565 - vec - The global vector to set values of 2566 2567 Level: advanced 2568 2569 Notes: 2570 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. 2571 2572 Calling sequence: 2573 .vb 2574 DMCreate(PETSC_COMM_WORLD, &dm); 2575 DMSetType(dm, DMPLEX); 2576 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2577 DMPlexTopologyLoad(dm, viewer, &sfX); 2578 DMClone(dm, §iondm); 2579 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2580 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2581 DMGetGlobalVector(sectiondm, &vec); 2582 PetscObjectSetName((PetscObject)vec, "vec_name"); 2583 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2584 DMRestoreGlobalVector(sectiondm, &vec); 2585 PetscSFDestroy(&gsf); 2586 PetscSFDestroy(&sfX); 2587 DMDestroy(§iondm); 2588 DMDestroy(&dm); 2589 .ve 2590 2591 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2592 `PetscSF`, `PetscViewer` 2593 @*/ 2594 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2595 { 2596 PetscBool ishdf5; 2597 2598 PetscFunctionBegin; 2599 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2600 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2601 if (!sectiondm) sectiondm = dm; 2602 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2603 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2604 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2605 /* Check consistency */ 2606 { 2607 PetscSection section; 2608 PetscBool includesConstraints; 2609 PetscInt m, m1; 2610 2611 PetscCall(VecGetLocalSize(vec, &m1)); 2612 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2613 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2614 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2615 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2616 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2617 } 2618 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2619 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2620 if (ishdf5) { 2621 #if defined(PETSC_HAVE_HDF5) 2622 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2623 #else 2624 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2625 #endif 2626 } 2627 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2628 PetscFunctionReturn(PETSC_SUCCESS); 2629 } 2630 2631 /*@ 2632 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2633 2634 Collective 2635 2636 Input Parameters: 2637 + dm - The `DM` that represents the topology 2638 . viewer - The `PetscViewer` that represents the on-disk vector data 2639 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2640 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2641 - vec - The local vector to set values of 2642 2643 Level: advanced 2644 2645 Notes: 2646 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. 2647 2648 Calling sequence: 2649 .vb 2650 DMCreate(PETSC_COMM_WORLD, &dm); 2651 DMSetType(dm, DMPLEX); 2652 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2653 DMPlexTopologyLoad(dm, viewer, &sfX); 2654 DMClone(dm, §iondm); 2655 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2656 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2657 DMGetLocalVector(sectiondm, &vec); 2658 PetscObjectSetName((PetscObject)vec, "vec_name"); 2659 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2660 DMRestoreLocalVector(sectiondm, &vec); 2661 PetscSFDestroy(&lsf); 2662 PetscSFDestroy(&sfX); 2663 DMDestroy(§iondm); 2664 DMDestroy(&dm); 2665 .ve 2666 2667 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2668 `PetscSF`, `PetscViewer` 2669 @*/ 2670 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2671 { 2672 PetscBool ishdf5; 2673 2674 PetscFunctionBegin; 2675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2676 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2677 if (!sectiondm) sectiondm = dm; 2678 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2679 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2680 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2681 /* Check consistency */ 2682 { 2683 PetscSection section; 2684 PetscBool includesConstraints; 2685 PetscInt m, m1; 2686 2687 PetscCall(VecGetLocalSize(vec, &m1)); 2688 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2689 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2690 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2691 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2692 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2693 } 2694 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2695 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2696 if (ishdf5) { 2697 #if defined(PETSC_HAVE_HDF5) 2698 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2699 #else 2700 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2701 #endif 2702 } 2703 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2704 PetscFunctionReturn(PETSC_SUCCESS); 2705 } 2706 2707 PetscErrorCode DMDestroy_Plex(DM dm) 2708 { 2709 DM_Plex *mesh = (DM_Plex *)dm->data; 2710 2711 PetscFunctionBegin; 2712 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2713 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2714 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2715 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2716 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2717 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2718 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2719 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2720 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2721 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2722 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2723 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2724 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2725 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2726 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2727 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2728 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2729 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2730 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2731 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2732 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2733 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2734 PetscCall(PetscFree(mesh->cones)); 2735 PetscCall(PetscFree(mesh->coneOrientations)); 2736 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2737 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2738 PetscCall(PetscFree(mesh->supports)); 2739 PetscCall(PetscFree(mesh->cellTypes)); 2740 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2741 PetscCall(PetscFree(mesh->tetgenOpts)); 2742 PetscCall(PetscFree(mesh->triangleOpts)); 2743 PetscCall(PetscFree(mesh->transformType)); 2744 PetscCall(PetscFree(mesh->distributionName)); 2745 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2746 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2747 PetscCall(ISDestroy(&mesh->subpointIS)); 2748 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2749 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2750 if (mesh->periodic.face_sfs) { 2751 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2752 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2753 } 2754 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2755 if (mesh->periodic.periodic_points) { 2756 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2757 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2758 } 2759 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2760 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2761 PetscCall(ISDestroy(&mesh->anchorIS)); 2762 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2763 PetscCall(PetscFree(mesh->parents)); 2764 PetscCall(PetscFree(mesh->childIDs)); 2765 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2766 PetscCall(PetscFree(mesh->children)); 2767 PetscCall(DMDestroy(&mesh->referenceTree)); 2768 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2769 PetscCall(PetscFree(mesh->neighbors)); 2770 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2771 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2772 PetscCall(PetscFree(mesh)); 2773 PetscFunctionReturn(PETSC_SUCCESS); 2774 } 2775 2776 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2777 { 2778 PetscSection sectionGlobal, sectionLocal; 2779 PetscInt bs = -1, mbs; 2780 PetscInt localSize, localStart = 0; 2781 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2782 MatType mtype; 2783 ISLocalToGlobalMapping ltog; 2784 2785 PetscFunctionBegin; 2786 PetscCall(MatInitializePackage()); 2787 mtype = dm->mattype; 2788 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2789 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2790 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2791 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2792 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2793 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2794 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2795 PetscCall(MatSetType(*J, mtype)); 2796 PetscCall(MatSetFromOptions(*J)); 2797 PetscCall(MatGetBlockSize(*J, &mbs)); 2798 if (mbs > 1) bs = mbs; 2799 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2800 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2801 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2802 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2803 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2804 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2805 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2806 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2807 if (!isShell) { 2808 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2809 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2810 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2811 2812 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2813 2814 PetscCall(PetscCalloc1(localSize, &pblocks)); 2815 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2816 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2817 for (p = pStart; p < pEnd; ++p) { 2818 switch (dm->blocking_type) { 2819 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2820 PetscInt bdof, offset; 2821 2822 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2823 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2824 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2825 if (dof > 0) { 2826 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2827 // Signal block concatenation 2828 if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof); 2829 } 2830 dof = dof < 0 ? -(dof + 1) : dof; 2831 bdof = cdof && (dof - cdof) ? 1 : dof; 2832 if (dof) { 2833 if (bs < 0) { 2834 bs = bdof; 2835 } else if (bs != bdof) { 2836 bs = 1; 2837 } 2838 } 2839 } break; 2840 case DM_BLOCKING_FIELD_NODE: { 2841 for (PetscInt field = 0; field < num_fields; field++) { 2842 PetscInt num_comp, bdof, offset; 2843 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2844 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2845 if (dof < 0) continue; 2846 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2847 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2848 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); 2849 PetscInt num_nodes = dof / num_comp; 2850 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2851 // Handle possibly constant block size (unlikely) 2852 bdof = cdof && (dof - cdof) ? 1 : dof; 2853 if (dof) { 2854 if (bs < 0) { 2855 bs = bdof; 2856 } else if (bs != bdof) { 2857 bs = 1; 2858 } 2859 } 2860 } 2861 } break; 2862 } 2863 } 2864 /* Must have same blocksize on all procs (some might have no points) */ 2865 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2866 bsLocal[1] = bs; 2867 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2868 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2869 else bs = bsMinMax[0]; 2870 bs = PetscMax(1, bs); 2871 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2872 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2873 PetscCall(MatSetBlockSize(*J, bs)); 2874 PetscCall(MatSetUp(*J)); 2875 } else { 2876 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2877 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2878 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2879 } 2880 if (pblocks) { // Consolidate blocks 2881 PetscInt nblocks = 0; 2882 pblocks[0] = PetscAbs(pblocks[0]); 2883 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2884 if (pblocks[i] == 0) continue; 2885 // Negative block size indicates the blocks should be concatenated 2886 if (pblocks[i] < 0) { 2887 pblocks[i] = -pblocks[i]; 2888 pblocks[nblocks - 1] += pblocks[i]; 2889 } else { 2890 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2891 } 2892 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]); 2893 } 2894 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2895 } 2896 PetscCall(PetscFree(pblocks)); 2897 } 2898 PetscCall(MatSetDM(*J, dm)); 2899 PetscFunctionReturn(PETSC_SUCCESS); 2900 } 2901 2902 /*@ 2903 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2904 2905 Not Collective 2906 2907 Input Parameter: 2908 . dm - The `DMPLEX` 2909 2910 Output Parameter: 2911 . subsection - The subdomain section 2912 2913 Level: developer 2914 2915 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2916 @*/ 2917 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2918 { 2919 DM_Plex *mesh = (DM_Plex *)dm->data; 2920 2921 PetscFunctionBegin; 2922 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2923 if (!mesh->subdomainSection) { 2924 PetscSection section; 2925 PetscSF sf; 2926 2927 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2928 PetscCall(DMGetLocalSection(dm, §ion)); 2929 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2930 PetscCall(PetscSFDestroy(&sf)); 2931 } 2932 *subsection = mesh->subdomainSection; 2933 PetscFunctionReturn(PETSC_SUCCESS); 2934 } 2935 2936 /*@ 2937 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2938 2939 Not Collective 2940 2941 Input Parameter: 2942 . dm - The `DMPLEX` 2943 2944 Output Parameters: 2945 + pStart - The first mesh point 2946 - pEnd - The upper bound for mesh points 2947 2948 Level: beginner 2949 2950 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2951 @*/ 2952 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2953 { 2954 DM_Plex *mesh = (DM_Plex *)dm->data; 2955 2956 PetscFunctionBegin; 2957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2958 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2959 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2960 PetscFunctionReturn(PETSC_SUCCESS); 2961 } 2962 2963 /*@ 2964 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2965 2966 Not Collective 2967 2968 Input Parameters: 2969 + dm - The `DMPLEX` 2970 . pStart - The first mesh point 2971 - pEnd - The upper bound for mesh points 2972 2973 Level: beginner 2974 2975 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2976 @*/ 2977 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2978 { 2979 DM_Plex *mesh = (DM_Plex *)dm->data; 2980 2981 PetscFunctionBegin; 2982 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2983 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2984 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2985 PetscCall(PetscFree(mesh->cellTypes)); 2986 PetscFunctionReturn(PETSC_SUCCESS); 2987 } 2988 2989 /*@ 2990 DMPlexGetConeSize - Return 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 2998 Output Parameter: 2999 . size - The cone size for point `p` 3000 3001 Level: beginner 3002 3003 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3004 @*/ 3005 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3006 { 3007 DM_Plex *mesh = (DM_Plex *)dm->data; 3008 3009 PetscFunctionBegin; 3010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3011 PetscAssertPointer(size, 3); 3012 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3013 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3014 PetscFunctionReturn(PETSC_SUCCESS); 3015 } 3016 3017 /*@ 3018 DMPlexSetConeSize - Set the number of 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 - size - The cone size for point `p` 3026 3027 Level: beginner 3028 3029 Note: 3030 This should be called after `DMPlexSetChart()`. 3031 3032 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3033 @*/ 3034 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3035 { 3036 DM_Plex *mesh = (DM_Plex *)dm->data; 3037 3038 PetscFunctionBegin; 3039 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3040 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3041 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3042 PetscFunctionReturn(PETSC_SUCCESS); 3043 } 3044 3045 /*@C 3046 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3047 3048 Not Collective 3049 3050 Input Parameters: 3051 + dm - The `DMPLEX` 3052 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3053 3054 Output Parameter: 3055 . cone - An array of points which are on the in-edges for point `p` 3056 3057 Level: beginner 3058 3059 Fortran Notes: 3060 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3061 `DMPlexRestoreCone()` is not needed/available in C. 3062 3063 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3064 @*/ 3065 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3066 { 3067 DM_Plex *mesh = (DM_Plex *)dm->data; 3068 PetscInt off; 3069 3070 PetscFunctionBegin; 3071 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3072 PetscAssertPointer(cone, 3); 3073 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3074 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3075 PetscFunctionReturn(PETSC_SUCCESS); 3076 } 3077 3078 /*@ 3079 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3080 3081 Not Collective 3082 3083 Input Parameters: 3084 + dm - The `DMPLEX` 3085 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3086 3087 Output Parameters: 3088 + pConesSection - `PetscSection` describing the layout of `pCones` 3089 - pCones - An array of points which are on the in-edges for the point set `p` 3090 3091 Level: intermediate 3092 3093 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3094 @*/ 3095 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3096 { 3097 PetscSection cs, newcs; 3098 PetscInt *cones; 3099 PetscInt *newarr = NULL; 3100 PetscInt n; 3101 3102 PetscFunctionBegin; 3103 PetscCall(DMPlexGetCones(dm, &cones)); 3104 PetscCall(DMPlexGetConeSection(dm, &cs)); 3105 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3106 if (pConesSection) *pConesSection = newcs; 3107 if (pCones) { 3108 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3109 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3110 } 3111 PetscFunctionReturn(PETSC_SUCCESS); 3112 } 3113 3114 /*@ 3115 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3116 3117 Not Collective 3118 3119 Input Parameters: 3120 + dm - The `DMPLEX` 3121 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3122 3123 Output Parameter: 3124 . expandedPoints - An array of vertices recursively expanded from input points 3125 3126 Level: advanced 3127 3128 Notes: 3129 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3130 3131 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3132 3133 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3134 `DMPlexGetDepth()`, `IS` 3135 @*/ 3136 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3137 { 3138 IS *expandedPointsAll; 3139 PetscInt depth; 3140 3141 PetscFunctionBegin; 3142 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3143 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3144 PetscAssertPointer(expandedPoints, 3); 3145 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3146 *expandedPoints = expandedPointsAll[0]; 3147 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3148 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3149 PetscFunctionReturn(PETSC_SUCCESS); 3150 } 3151 3152 /*@ 3153 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). 3154 3155 Not Collective 3156 3157 Input Parameters: 3158 + dm - The `DMPLEX` 3159 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3160 3161 Output Parameters: 3162 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3163 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3164 - sections - (optional) An array of sections which describe mappings from points to their cone points 3165 3166 Level: advanced 3167 3168 Notes: 3169 Like `DMPlexGetConeTuple()` but recursive. 3170 3171 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. 3172 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3173 3174 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\: 3175 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3176 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3177 3178 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3179 `DMPlexGetDepth()`, `PetscSection`, `IS` 3180 @*/ 3181 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3182 { 3183 const PetscInt *arr0 = NULL, *cone = NULL; 3184 PetscInt *arr = NULL, *newarr = NULL; 3185 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3186 IS *expandedPoints_; 3187 PetscSection *sections_; 3188 3189 PetscFunctionBegin; 3190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3191 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3192 if (depth) PetscAssertPointer(depth, 3); 3193 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3194 if (sections) PetscAssertPointer(sections, 5); 3195 PetscCall(ISGetLocalSize(points, &n)); 3196 PetscCall(ISGetIndices(points, &arr0)); 3197 PetscCall(DMPlexGetDepth(dm, &depth_)); 3198 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3199 PetscCall(PetscCalloc1(depth_, §ions_)); 3200 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3201 for (d = depth_ - 1; d >= 0; d--) { 3202 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3203 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3204 for (i = 0; i < n; i++) { 3205 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3206 if (arr[i] >= start && arr[i] < end) { 3207 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3208 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3209 } else { 3210 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3211 } 3212 } 3213 PetscCall(PetscSectionSetUp(sections_[d])); 3214 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3215 PetscCall(PetscMalloc1(newn, &newarr)); 3216 for (i = 0; i < n; i++) { 3217 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3218 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3219 if (cn > 1) { 3220 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3221 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3222 } else { 3223 newarr[co] = arr[i]; 3224 } 3225 } 3226 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3227 arr = newarr; 3228 n = newn; 3229 } 3230 PetscCall(ISRestoreIndices(points, &arr0)); 3231 *depth = depth_; 3232 if (expandedPoints) *expandedPoints = expandedPoints_; 3233 else { 3234 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3235 PetscCall(PetscFree(expandedPoints_)); 3236 } 3237 if (sections) *sections = sections_; 3238 else { 3239 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3240 PetscCall(PetscFree(sections_)); 3241 } 3242 PetscFunctionReturn(PETSC_SUCCESS); 3243 } 3244 3245 /*@ 3246 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3247 3248 Not Collective 3249 3250 Input Parameters: 3251 + dm - The `DMPLEX` 3252 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3253 3254 Output Parameters: 3255 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3256 . expandedPoints - (optional) An array of recursively expanded cones 3257 - sections - (optional) An array of sections which describe mappings from points to their cone points 3258 3259 Level: advanced 3260 3261 Note: 3262 See `DMPlexGetConeRecursive()` 3263 3264 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3265 `DMPlexGetDepth()`, `IS`, `PetscSection` 3266 @*/ 3267 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3268 { 3269 PetscInt d, depth_; 3270 3271 PetscFunctionBegin; 3272 PetscCall(DMPlexGetDepth(dm, &depth_)); 3273 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3274 if (depth) *depth = 0; 3275 if (expandedPoints) { 3276 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3277 PetscCall(PetscFree(*expandedPoints)); 3278 } 3279 if (sections) { 3280 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3281 PetscCall(PetscFree(*sections)); 3282 } 3283 PetscFunctionReturn(PETSC_SUCCESS); 3284 } 3285 3286 /*@ 3287 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 3288 3289 Not Collective 3290 3291 Input Parameters: 3292 + dm - The `DMPLEX` 3293 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3294 - cone - An array of points which are on the in-edges for point `p` 3295 3296 Level: beginner 3297 3298 Note: 3299 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3300 3301 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3302 @*/ 3303 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3304 { 3305 DM_Plex *mesh = (DM_Plex *)dm->data; 3306 PetscInt dof, off, c; 3307 3308 PetscFunctionBegin; 3309 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3310 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3311 if (dof) PetscAssertPointer(cone, 3); 3312 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3313 if (PetscDefined(USE_DEBUG)) { 3314 PetscInt pStart, pEnd; 3315 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3316 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); 3317 for (c = 0; c < dof; ++c) { 3318 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); 3319 mesh->cones[off + c] = cone[c]; 3320 } 3321 } else { 3322 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3323 } 3324 PetscFunctionReturn(PETSC_SUCCESS); 3325 } 3326 3327 /*@C 3328 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3329 3330 Not Collective 3331 3332 Input Parameters: 3333 + dm - The `DMPLEX` 3334 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3335 3336 Output Parameter: 3337 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3338 integer giving the prescription for cone traversal. 3339 3340 Level: beginner 3341 3342 Note: 3343 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3344 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3345 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3346 with the identity. 3347 3348 Fortran Notes: 3349 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3350 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3351 3352 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3353 @*/ 3354 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3355 { 3356 DM_Plex *mesh = (DM_Plex *)dm->data; 3357 PetscInt off; 3358 3359 PetscFunctionBegin; 3360 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3361 if (PetscDefined(USE_DEBUG)) { 3362 PetscInt dof; 3363 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3364 if (dof) PetscAssertPointer(coneOrientation, 3); 3365 } 3366 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3367 3368 *coneOrientation = &mesh->coneOrientations[off]; 3369 PetscFunctionReturn(PETSC_SUCCESS); 3370 } 3371 3372 /*@ 3373 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3374 3375 Not Collective 3376 3377 Input Parameters: 3378 + dm - The `DMPLEX` 3379 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3380 - coneOrientation - An array of orientations 3381 3382 Level: beginner 3383 3384 Notes: 3385 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3386 3387 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3388 3389 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3390 @*/ 3391 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3392 { 3393 DM_Plex *mesh = (DM_Plex *)dm->data; 3394 PetscInt pStart, pEnd; 3395 PetscInt dof, off, c; 3396 3397 PetscFunctionBegin; 3398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3399 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3400 if (dof) PetscAssertPointer(coneOrientation, 3); 3401 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3402 if (PetscDefined(USE_DEBUG)) { 3403 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3404 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); 3405 for (c = 0; c < dof; ++c) { 3406 PetscInt cdof, o = coneOrientation[c]; 3407 3408 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3409 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); 3410 mesh->coneOrientations[off + c] = o; 3411 } 3412 } else { 3413 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3414 } 3415 PetscFunctionReturn(PETSC_SUCCESS); 3416 } 3417 3418 /*@ 3419 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3420 3421 Not Collective 3422 3423 Input Parameters: 3424 + dm - The `DMPLEX` 3425 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3426 . conePos - The local index in the cone where the point should be put 3427 - conePoint - The mesh point to insert 3428 3429 Level: beginner 3430 3431 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3432 @*/ 3433 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3434 { 3435 DM_Plex *mesh = (DM_Plex *)dm->data; 3436 PetscInt pStart, pEnd; 3437 PetscInt dof, off; 3438 3439 PetscFunctionBegin; 3440 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3441 if (PetscDefined(USE_DEBUG)) { 3442 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3443 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); 3444 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); 3445 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3446 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); 3447 } 3448 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3449 mesh->cones[off + conePos] = conePoint; 3450 PetscFunctionReturn(PETSC_SUCCESS); 3451 } 3452 3453 /*@ 3454 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3455 3456 Not Collective 3457 3458 Input Parameters: 3459 + dm - The `DMPLEX` 3460 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3461 . conePos - The local index in the cone where the point should be put 3462 - coneOrientation - The point orientation to insert 3463 3464 Level: beginner 3465 3466 Note: 3467 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3468 3469 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3470 @*/ 3471 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3472 { 3473 DM_Plex *mesh = (DM_Plex *)dm->data; 3474 PetscInt pStart, pEnd; 3475 PetscInt dof, off; 3476 3477 PetscFunctionBegin; 3478 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3479 if (PetscDefined(USE_DEBUG)) { 3480 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3481 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); 3482 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3483 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); 3484 } 3485 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3486 mesh->coneOrientations[off + conePos] = coneOrientation; 3487 PetscFunctionReturn(PETSC_SUCCESS); 3488 } 3489 3490 /*@C 3491 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3492 3493 Not collective 3494 3495 Input Parameters: 3496 + dm - The DMPlex 3497 - p - The point, which must lie in the chart set with DMPlexSetChart() 3498 3499 Output Parameters: 3500 + cone - An array of points which are on the in-edges for point `p` 3501 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3502 integer giving the prescription for cone traversal. 3503 3504 Level: beginner 3505 3506 Notes: 3507 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3508 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3509 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3510 with the identity. 3511 3512 Fortran Notes: 3513 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3514 `DMPlexRestoreCone()` is not needed/available in C. 3515 3516 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3517 @*/ 3518 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3519 { 3520 DM_Plex *mesh = (DM_Plex *)dm->data; 3521 3522 PetscFunctionBegin; 3523 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3524 if (mesh->tr) { 3525 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3526 } else { 3527 PetscInt off; 3528 if (PetscDefined(USE_DEBUG)) { 3529 PetscInt dof; 3530 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3531 if (dof) { 3532 if (cone) PetscAssertPointer(cone, 3); 3533 if (ornt) PetscAssertPointer(ornt, 4); 3534 } 3535 } 3536 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3537 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3538 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3539 } 3540 PetscFunctionReturn(PETSC_SUCCESS); 3541 } 3542 3543 /*@C 3544 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3545 3546 Not Collective 3547 3548 Input Parameters: 3549 + dm - The DMPlex 3550 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3551 . cone - An array of points which are on the in-edges for point p 3552 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3553 integer giving the prescription for cone traversal. 3554 3555 Level: beginner 3556 3557 Notes: 3558 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3559 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3560 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3561 with the identity. 3562 3563 Fortran Notes: 3564 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3565 `DMPlexRestoreCone()` is not needed/available in C. 3566 3567 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3568 @*/ 3569 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3570 { 3571 DM_Plex *mesh = (DM_Plex *)dm->data; 3572 3573 PetscFunctionBegin; 3574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3575 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3576 PetscFunctionReturn(PETSC_SUCCESS); 3577 } 3578 3579 /*@ 3580 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3581 3582 Not Collective 3583 3584 Input Parameters: 3585 + dm - The `DMPLEX` 3586 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3587 3588 Output Parameter: 3589 . size - The support size for point `p` 3590 3591 Level: beginner 3592 3593 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3594 @*/ 3595 PetscErrorCode DMPlexGetSupportSize(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 PetscAssertPointer(size, 3); 3602 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3603 PetscFunctionReturn(PETSC_SUCCESS); 3604 } 3605 3606 /*@ 3607 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3608 3609 Not Collective 3610 3611 Input Parameters: 3612 + dm - The `DMPLEX` 3613 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3614 - size - The support size for point `p` 3615 3616 Level: beginner 3617 3618 Note: 3619 This should be called after `DMPlexSetChart()`. 3620 3621 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3622 @*/ 3623 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3624 { 3625 DM_Plex *mesh = (DM_Plex *)dm->data; 3626 3627 PetscFunctionBegin; 3628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3629 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3630 PetscFunctionReturn(PETSC_SUCCESS); 3631 } 3632 3633 /*@C 3634 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3635 3636 Not Collective 3637 3638 Input Parameters: 3639 + dm - The `DMPLEX` 3640 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3641 3642 Output Parameter: 3643 . support - An array of points which are on the out-edges for point `p` 3644 3645 Level: beginner 3646 3647 Fortran Notes: 3648 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3649 `DMPlexRestoreSupport()` is not needed/available in C. 3650 3651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3652 @*/ 3653 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3654 { 3655 DM_Plex *mesh = (DM_Plex *)dm->data; 3656 PetscInt off; 3657 3658 PetscFunctionBegin; 3659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3660 PetscAssertPointer(support, 3); 3661 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3662 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3663 PetscFunctionReturn(PETSC_SUCCESS); 3664 } 3665 3666 /*@ 3667 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3668 3669 Not Collective 3670 3671 Input Parameters: 3672 + dm - The `DMPLEX` 3673 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3674 - support - An array of points which are on the out-edges for point `p` 3675 3676 Level: beginner 3677 3678 Note: 3679 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3680 3681 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3682 @*/ 3683 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3684 { 3685 DM_Plex *mesh = (DM_Plex *)dm->data; 3686 PetscInt pStart, pEnd; 3687 PetscInt dof, off, c; 3688 3689 PetscFunctionBegin; 3690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3691 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3692 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3693 if (dof) PetscAssertPointer(support, 3); 3694 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3695 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); 3696 for (c = 0; c < dof; ++c) { 3697 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); 3698 mesh->supports[off + c] = support[c]; 3699 } 3700 PetscFunctionReturn(PETSC_SUCCESS); 3701 } 3702 3703 /*@ 3704 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3705 3706 Not Collective 3707 3708 Input Parameters: 3709 + dm - The `DMPLEX` 3710 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3711 . supportPos - The local index in the cone where the point should be put 3712 - supportPoint - The mesh point to insert 3713 3714 Level: beginner 3715 3716 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3717 @*/ 3718 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3719 { 3720 DM_Plex *mesh = (DM_Plex *)dm->data; 3721 PetscInt pStart, pEnd; 3722 PetscInt dof, off; 3723 3724 PetscFunctionBegin; 3725 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3726 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3727 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3728 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3729 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); 3730 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); 3731 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); 3732 mesh->supports[off + supportPos] = supportPoint; 3733 PetscFunctionReturn(PETSC_SUCCESS); 3734 } 3735 3736 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3737 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3738 { 3739 switch (ct) { 3740 case DM_POLYTOPE_SEGMENT: 3741 if (o == -1) return -2; 3742 break; 3743 case DM_POLYTOPE_TRIANGLE: 3744 if (o == -3) return -1; 3745 if (o == -2) return -3; 3746 if (o == -1) return -2; 3747 break; 3748 case DM_POLYTOPE_QUADRILATERAL: 3749 if (o == -4) return -2; 3750 if (o == -3) return -1; 3751 if (o == -2) return -4; 3752 if (o == -1) return -3; 3753 break; 3754 default: 3755 return o; 3756 } 3757 return o; 3758 } 3759 3760 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3761 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3762 { 3763 switch (ct) { 3764 case DM_POLYTOPE_SEGMENT: 3765 if ((o == -2) || (o == 1)) return -1; 3766 if (o == -1) return 0; 3767 break; 3768 case DM_POLYTOPE_TRIANGLE: 3769 if (o == -3) return -2; 3770 if (o == -2) return -1; 3771 if (o == -1) return -3; 3772 break; 3773 case DM_POLYTOPE_QUADRILATERAL: 3774 if (o == -4) return -2; 3775 if (o == -3) return -1; 3776 if (o == -2) return -4; 3777 if (o == -1) return -3; 3778 break; 3779 default: 3780 return o; 3781 } 3782 return o; 3783 } 3784 3785 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3786 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3787 { 3788 PetscInt pStart, pEnd, p; 3789 3790 PetscFunctionBegin; 3791 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3792 for (p = pStart; p < pEnd; ++p) { 3793 const PetscInt *cone, *ornt; 3794 PetscInt coneSize, c; 3795 3796 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3797 PetscCall(DMPlexGetCone(dm, p, &cone)); 3798 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3799 for (c = 0; c < coneSize; ++c) { 3800 DMPolytopeType ct; 3801 const PetscInt o = ornt[c]; 3802 3803 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3804 switch (ct) { 3805 case DM_POLYTOPE_SEGMENT: 3806 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3807 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3808 break; 3809 case DM_POLYTOPE_TRIANGLE: 3810 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3811 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3812 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3813 break; 3814 case DM_POLYTOPE_QUADRILATERAL: 3815 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3816 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3817 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3818 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3819 break; 3820 default: 3821 break; 3822 } 3823 } 3824 } 3825 PetscFunctionReturn(PETSC_SUCCESS); 3826 } 3827 3828 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3829 { 3830 DM_Plex *mesh = (DM_Plex *)dm->data; 3831 3832 PetscFunctionBeginHot; 3833 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3834 if (useCone) { 3835 PetscCall(DMPlexGetConeSize(dm, p, size)); 3836 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3837 } else { 3838 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3839 PetscCall(DMPlexGetSupport(dm, p, arr)); 3840 } 3841 } else { 3842 if (useCone) { 3843 const PetscSection s = mesh->coneSection; 3844 const PetscInt ps = p - s->pStart; 3845 const PetscInt off = s->atlasOff[ps]; 3846 3847 *size = s->atlasDof[ps]; 3848 *arr = mesh->cones + off; 3849 *ornt = mesh->coneOrientations + off; 3850 } else { 3851 const PetscSection s = mesh->supportSection; 3852 const PetscInt ps = p - s->pStart; 3853 const PetscInt off = s->atlasOff[ps]; 3854 3855 *size = s->atlasDof[ps]; 3856 *arr = mesh->supports + off; 3857 } 3858 } 3859 PetscFunctionReturn(PETSC_SUCCESS); 3860 } 3861 3862 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3863 { 3864 DM_Plex *mesh = (DM_Plex *)dm->data; 3865 3866 PetscFunctionBeginHot; 3867 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3868 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3869 } 3870 PetscFunctionReturn(PETSC_SUCCESS); 3871 } 3872 3873 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3874 { 3875 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3876 PetscInt *closure; 3877 const PetscInt *tmp = NULL, *tmpO = NULL; 3878 PetscInt off = 0, tmpSize, t; 3879 3880 PetscFunctionBeginHot; 3881 if (ornt) { 3882 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3883 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; 3884 } 3885 if (*points) { 3886 closure = *points; 3887 } else { 3888 PetscInt maxConeSize, maxSupportSize; 3889 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3890 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3891 } 3892 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3893 if (ct == DM_POLYTOPE_UNKNOWN) { 3894 closure[off++] = p; 3895 closure[off++] = 0; 3896 for (t = 0; t < tmpSize; ++t) { 3897 closure[off++] = tmp[t]; 3898 closure[off++] = tmpO ? tmpO[t] : 0; 3899 } 3900 } else { 3901 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3902 3903 /* We assume that cells with a valid type have faces with a valid type */ 3904 closure[off++] = p; 3905 closure[off++] = ornt; 3906 for (t = 0; t < tmpSize; ++t) { 3907 DMPolytopeType ft; 3908 3909 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3910 closure[off++] = tmp[arr[t]]; 3911 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3912 } 3913 } 3914 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3915 if (numPoints) *numPoints = tmpSize + 1; 3916 if (points) *points = closure; 3917 PetscFunctionReturn(PETSC_SUCCESS); 3918 } 3919 3920 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3921 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3922 { 3923 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3924 const PetscInt *cone, *ornt; 3925 PetscInt *pts, *closure = NULL; 3926 DMPolytopeType ft; 3927 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3928 PetscInt dim, coneSize, c, d, clSize, cl; 3929 3930 PetscFunctionBeginHot; 3931 PetscCall(DMGetDimension(dm, &dim)); 3932 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3933 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3934 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3935 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3936 maxSize = PetscMax(coneSeries, supportSeries); 3937 if (*points) { 3938 pts = *points; 3939 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3940 c = 0; 3941 pts[c++] = point; 3942 pts[c++] = o; 3943 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3944 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3945 for (cl = 0; cl < clSize * 2; cl += 2) { 3946 pts[c++] = closure[cl]; 3947 pts[c++] = closure[cl + 1]; 3948 } 3949 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3950 for (cl = 0; cl < clSize * 2; cl += 2) { 3951 pts[c++] = closure[cl]; 3952 pts[c++] = closure[cl + 1]; 3953 } 3954 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3955 for (d = 2; d < coneSize; ++d) { 3956 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3957 pts[c++] = cone[arr[d * 2 + 0]]; 3958 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3959 } 3960 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3961 if (dim >= 3) { 3962 for (d = 2; d < coneSize; ++d) { 3963 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3964 const PetscInt *fcone, *fornt; 3965 PetscInt fconeSize, fc, i; 3966 3967 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3968 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3969 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3970 for (fc = 0; fc < fconeSize; ++fc) { 3971 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3972 const PetscInt co = farr[fc * 2 + 1]; 3973 3974 for (i = 0; i < c; i += 2) 3975 if (pts[i] == cp) break; 3976 if (i == c) { 3977 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3978 pts[c++] = cp; 3979 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3980 } 3981 } 3982 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3983 } 3984 } 3985 *numPoints = c / 2; 3986 *points = pts; 3987 PetscFunctionReturn(PETSC_SUCCESS); 3988 } 3989 3990 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3991 { 3992 DMPolytopeType ct; 3993 PetscInt *closure, *fifo; 3994 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3995 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3996 PetscInt depth, maxSize; 3997 3998 PetscFunctionBeginHot; 3999 PetscCall(DMPlexGetDepth(dm, &depth)); 4000 if (depth == 1) { 4001 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4002 PetscFunctionReturn(PETSC_SUCCESS); 4003 } 4004 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4005 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; 4006 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4007 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4008 PetscFunctionReturn(PETSC_SUCCESS); 4009 } 4010 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4011 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4012 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4013 maxSize = PetscMax(coneSeries, supportSeries); 4014 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4015 if (*points) { 4016 closure = *points; 4017 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4018 closure[closureSize++] = p; 4019 closure[closureSize++] = ornt; 4020 fifo[fifoSize++] = p; 4021 fifo[fifoSize++] = ornt; 4022 fifo[fifoSize++] = ct; 4023 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4024 while (fifoSize - fifoStart) { 4025 const PetscInt q = fifo[fifoStart++]; 4026 const PetscInt o = fifo[fifoStart++]; 4027 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4028 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4029 const PetscInt *tmp, *tmpO = NULL; 4030 PetscInt tmpSize, t; 4031 4032 if (PetscDefined(USE_DEBUG)) { 4033 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4034 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); 4035 } 4036 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4037 for (t = 0; t < tmpSize; ++t) { 4038 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4039 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4040 const PetscInt cp = tmp[ip]; 4041 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4042 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4043 PetscInt c; 4044 4045 /* Check for duplicate */ 4046 for (c = 0; c < closureSize; c += 2) { 4047 if (closure[c] == cp) break; 4048 } 4049 if (c == closureSize) { 4050 closure[closureSize++] = cp; 4051 closure[closureSize++] = co; 4052 fifo[fifoSize++] = cp; 4053 fifo[fifoSize++] = co; 4054 fifo[fifoSize++] = ct; 4055 } 4056 } 4057 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4058 } 4059 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4060 if (numPoints) *numPoints = closureSize / 2; 4061 if (points) *points = closure; 4062 PetscFunctionReturn(PETSC_SUCCESS); 4063 } 4064 4065 /*@C 4066 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4067 4068 Not Collective 4069 4070 Input Parameters: 4071 + dm - The `DMPLEX` 4072 . p - The mesh point 4073 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4074 4075 Input/Output Parameter: 4076 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4077 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4078 4079 Output Parameter: 4080 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4081 4082 Level: beginner 4083 4084 Note: 4085 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4086 4087 Fortran Notes: 4088 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4089 4090 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4091 @*/ 4092 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4093 { 4094 PetscFunctionBeginHot; 4095 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4096 if (numPoints) PetscAssertPointer(numPoints, 4); 4097 if (points) PetscAssertPointer(points, 5); 4098 if (PetscDefined(USE_DEBUG)) { 4099 PetscInt pStart, pEnd; 4100 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4101 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4102 } 4103 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4104 PetscFunctionReturn(PETSC_SUCCESS); 4105 } 4106 4107 /*@C 4108 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4109 4110 Not Collective 4111 4112 Input Parameters: 4113 + dm - The `DMPLEX` 4114 . p - The mesh point 4115 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4116 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4117 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4118 4119 Level: beginner 4120 4121 Note: 4122 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4123 4124 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4125 @*/ 4126 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4127 { 4128 PetscFunctionBeginHot; 4129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4130 if (numPoints) *numPoints = 0; 4131 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4132 PetscFunctionReturn(PETSC_SUCCESS); 4133 } 4134 4135 /*@ 4136 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4137 4138 Not Collective 4139 4140 Input Parameter: 4141 . dm - The `DMPLEX` 4142 4143 Output Parameters: 4144 + maxConeSize - The maximum number of in-edges 4145 - maxSupportSize - The maximum number of out-edges 4146 4147 Level: beginner 4148 4149 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4150 @*/ 4151 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4152 { 4153 DM_Plex *mesh = (DM_Plex *)dm->data; 4154 4155 PetscFunctionBegin; 4156 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4157 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4158 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4159 PetscFunctionReturn(PETSC_SUCCESS); 4160 } 4161 4162 PetscErrorCode DMSetUp_Plex(DM dm) 4163 { 4164 DM_Plex *mesh = (DM_Plex *)dm->data; 4165 PetscInt size, maxSupportSize; 4166 4167 PetscFunctionBegin; 4168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4169 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4170 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4171 PetscCall(PetscMalloc1(size, &mesh->cones)); 4172 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4173 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4174 if (maxSupportSize) { 4175 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4176 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4177 PetscCall(PetscMalloc1(size, &mesh->supports)); 4178 } 4179 PetscFunctionReturn(PETSC_SUCCESS); 4180 } 4181 4182 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4183 { 4184 PetscFunctionBegin; 4185 if (subdm) PetscCall(DMClone(dm, subdm)); 4186 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4187 if (subdm) (*subdm)->useNatural = dm->useNatural; 4188 if (dm->useNatural && dm->sfMigration) { 4189 PetscSF sfNatural; 4190 4191 (*subdm)->sfMigration = dm->sfMigration; 4192 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4193 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4194 (*subdm)->sfNatural = sfNatural; 4195 } 4196 PetscFunctionReturn(PETSC_SUCCESS); 4197 } 4198 4199 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4200 { 4201 PetscInt i = 0; 4202 4203 PetscFunctionBegin; 4204 PetscCall(DMClone(dms[0], superdm)); 4205 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4206 (*superdm)->useNatural = PETSC_FALSE; 4207 for (i = 0; i < len; i++) { 4208 if (dms[i]->useNatural && dms[i]->sfMigration) { 4209 PetscSF sfNatural; 4210 4211 (*superdm)->sfMigration = dms[i]->sfMigration; 4212 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4213 (*superdm)->useNatural = PETSC_TRUE; 4214 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4215 (*superdm)->sfNatural = sfNatural; 4216 break; 4217 } 4218 } 4219 PetscFunctionReturn(PETSC_SUCCESS); 4220 } 4221 4222 /*@ 4223 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4224 4225 Not Collective 4226 4227 Input Parameter: 4228 . dm - The `DMPLEX` 4229 4230 Level: beginner 4231 4232 Note: 4233 This should be called after all calls to `DMPlexSetCone()` 4234 4235 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4236 @*/ 4237 PetscErrorCode DMPlexSymmetrize(DM dm) 4238 { 4239 DM_Plex *mesh = (DM_Plex *)dm->data; 4240 PetscInt *offsets; 4241 PetscInt supportSize; 4242 PetscInt pStart, pEnd, p; 4243 4244 PetscFunctionBegin; 4245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4246 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4247 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4248 /* Calculate support sizes */ 4249 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4250 for (p = pStart; p < pEnd; ++p) { 4251 PetscInt dof, off, c; 4252 4253 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4254 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4255 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4256 } 4257 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4258 /* Calculate supports */ 4259 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4260 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4261 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4262 for (p = pStart; p < pEnd; ++p) { 4263 PetscInt dof, off, c; 4264 4265 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4266 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4267 for (c = off; c < off + dof; ++c) { 4268 const PetscInt q = mesh->cones[c]; 4269 PetscInt offS; 4270 4271 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4272 4273 mesh->supports[offS + offsets[q]] = p; 4274 ++offsets[q]; 4275 } 4276 } 4277 PetscCall(PetscFree(offsets)); 4278 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4279 PetscFunctionReturn(PETSC_SUCCESS); 4280 } 4281 4282 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4283 { 4284 IS stratumIS; 4285 4286 PetscFunctionBegin; 4287 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4288 if (PetscDefined(USE_DEBUG)) { 4289 PetscInt qStart, qEnd, numLevels, level; 4290 PetscBool overlap = PETSC_FALSE; 4291 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4292 for (level = 0; level < numLevels; level++) { 4293 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4294 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4295 overlap = PETSC_TRUE; 4296 break; 4297 } 4298 } 4299 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); 4300 } 4301 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4302 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4303 PetscCall(ISDestroy(&stratumIS)); 4304 PetscFunctionReturn(PETSC_SUCCESS); 4305 } 4306 4307 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4308 { 4309 PetscInt *pMin, *pMax; 4310 PetscInt pStart, pEnd; 4311 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4312 4313 PetscFunctionBegin; 4314 { 4315 DMLabel label2; 4316 4317 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4318 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4319 } 4320 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4321 for (PetscInt p = pStart; p < pEnd; ++p) { 4322 DMPolytopeType ct; 4323 4324 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4325 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4326 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4327 } 4328 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4329 for (PetscInt d = dmin; d <= dmax; ++d) { 4330 pMin[d] = PETSC_MAX_INT; 4331 pMax[d] = PETSC_MIN_INT; 4332 } 4333 for (PetscInt p = pStart; p < pEnd; ++p) { 4334 DMPolytopeType ct; 4335 PetscInt d; 4336 4337 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4338 d = DMPolytopeTypeGetDim(ct); 4339 pMin[d] = PetscMin(p, pMin[d]); 4340 pMax[d] = PetscMax(p, pMax[d]); 4341 } 4342 for (PetscInt d = dmin; d <= dmax; ++d) { 4343 if (pMin[d] > pMax[d]) continue; 4344 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4345 } 4346 PetscCall(PetscFree2(pMin, pMax)); 4347 PetscFunctionReturn(PETSC_SUCCESS); 4348 } 4349 4350 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4351 { 4352 PetscInt pStart, pEnd; 4353 PetscInt numRoots = 0, numLeaves = 0; 4354 4355 PetscFunctionBegin; 4356 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4357 { 4358 /* Initialize roots and count leaves */ 4359 PetscInt sMin = PETSC_MAX_INT; 4360 PetscInt sMax = PETSC_MIN_INT; 4361 PetscInt coneSize, supportSize; 4362 4363 for (PetscInt p = pStart; p < pEnd; ++p) { 4364 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4365 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4366 if (!coneSize && supportSize) { 4367 sMin = PetscMin(p, sMin); 4368 sMax = PetscMax(p, sMax); 4369 ++numRoots; 4370 } else if (!supportSize && coneSize) { 4371 ++numLeaves; 4372 } else if (!supportSize && !coneSize) { 4373 /* Isolated points */ 4374 sMin = PetscMin(p, sMin); 4375 sMax = PetscMax(p, sMax); 4376 } 4377 } 4378 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4379 } 4380 4381 if (numRoots + numLeaves == (pEnd - pStart)) { 4382 PetscInt sMin = PETSC_MAX_INT; 4383 PetscInt sMax = PETSC_MIN_INT; 4384 PetscInt coneSize, supportSize; 4385 4386 for (PetscInt p = pStart; p < pEnd; ++p) { 4387 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4388 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4389 if (!supportSize && coneSize) { 4390 sMin = PetscMin(p, sMin); 4391 sMax = PetscMax(p, sMax); 4392 } 4393 } 4394 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4395 } else { 4396 PetscInt level = 0; 4397 PetscInt qStart, qEnd; 4398 4399 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4400 while (qEnd > qStart) { 4401 PetscInt sMin = PETSC_MAX_INT; 4402 PetscInt sMax = PETSC_MIN_INT; 4403 4404 for (PetscInt q = qStart; q < qEnd; ++q) { 4405 const PetscInt *support; 4406 PetscInt supportSize; 4407 4408 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4409 PetscCall(DMPlexGetSupport(dm, q, &support)); 4410 for (PetscInt s = 0; s < supportSize; ++s) { 4411 sMin = PetscMin(support[s], sMin); 4412 sMax = PetscMax(support[s], sMax); 4413 } 4414 } 4415 PetscCall(DMLabelGetNumValues(label, &level)); 4416 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4417 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4418 } 4419 } 4420 PetscFunctionReturn(PETSC_SUCCESS); 4421 } 4422 4423 /*@ 4424 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4425 4426 Collective 4427 4428 Input Parameter: 4429 . dm - The `DMPLEX` 4430 4431 Level: beginner 4432 4433 Notes: 4434 The strata group all points of the same grade, and this function calculates the strata. This 4435 grade can be seen as the height (or depth) of the point in the DAG. 4436 4437 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4438 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4439 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4440 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4441 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4442 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4443 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4444 4445 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4446 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4447 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 4448 to interpolate only that one (e0), so that 4449 .vb 4450 cone(c0) = {e0, v2} 4451 cone(e0) = {v0, v1} 4452 .ve 4453 If `DMPlexStratify()` is run on this mesh, it will give depths 4454 .vb 4455 depth 0 = {v0, v1, v2} 4456 depth 1 = {e0, c0} 4457 .ve 4458 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4459 4460 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4461 4462 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4463 @*/ 4464 PetscErrorCode DMPlexStratify(DM dm) 4465 { 4466 DM_Plex *mesh = (DM_Plex *)dm->data; 4467 DMLabel label; 4468 PetscBool flg = PETSC_FALSE; 4469 4470 PetscFunctionBegin; 4471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4472 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4473 4474 // Create depth label 4475 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4476 PetscCall(DMCreateLabel(dm, "depth")); 4477 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4478 4479 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4480 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4481 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4482 4483 { /* just in case there is an empty process */ 4484 PetscInt numValues, maxValues = 0, v; 4485 4486 PetscCall(DMLabelGetNumValues(label, &numValues)); 4487 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4488 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4489 } 4490 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4491 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4492 PetscFunctionReturn(PETSC_SUCCESS); 4493 } 4494 4495 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4496 { 4497 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4498 PetscInt dim, depth, pheight, coneSize; 4499 4500 PetscFunctionBeginHot; 4501 PetscCall(DMGetDimension(dm, &dim)); 4502 PetscCall(DMPlexGetDepth(dm, &depth)); 4503 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4504 pheight = depth - pdepth; 4505 if (depth <= 1) { 4506 switch (pdepth) { 4507 case 0: 4508 ct = DM_POLYTOPE_POINT; 4509 break; 4510 case 1: 4511 switch (coneSize) { 4512 case 2: 4513 ct = DM_POLYTOPE_SEGMENT; 4514 break; 4515 case 3: 4516 ct = DM_POLYTOPE_TRIANGLE; 4517 break; 4518 case 4: 4519 switch (dim) { 4520 case 2: 4521 ct = DM_POLYTOPE_QUADRILATERAL; 4522 break; 4523 case 3: 4524 ct = DM_POLYTOPE_TETRAHEDRON; 4525 break; 4526 default: 4527 break; 4528 } 4529 break; 4530 case 5: 4531 ct = DM_POLYTOPE_PYRAMID; 4532 break; 4533 case 6: 4534 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4535 break; 4536 case 8: 4537 ct = DM_POLYTOPE_HEXAHEDRON; 4538 break; 4539 default: 4540 break; 4541 } 4542 } 4543 } else { 4544 if (pdepth == 0) { 4545 ct = DM_POLYTOPE_POINT; 4546 } else if (pheight == 0) { 4547 switch (dim) { 4548 case 1: 4549 switch (coneSize) { 4550 case 2: 4551 ct = DM_POLYTOPE_SEGMENT; 4552 break; 4553 default: 4554 break; 4555 } 4556 break; 4557 case 2: 4558 switch (coneSize) { 4559 case 3: 4560 ct = DM_POLYTOPE_TRIANGLE; 4561 break; 4562 case 4: 4563 ct = DM_POLYTOPE_QUADRILATERAL; 4564 break; 4565 default: 4566 break; 4567 } 4568 break; 4569 case 3: 4570 switch (coneSize) { 4571 case 4: 4572 ct = DM_POLYTOPE_TETRAHEDRON; 4573 break; 4574 case 5: { 4575 const PetscInt *cone; 4576 PetscInt faceConeSize; 4577 4578 PetscCall(DMPlexGetCone(dm, p, &cone)); 4579 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4580 switch (faceConeSize) { 4581 case 3: 4582 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4583 break; 4584 case 4: 4585 ct = DM_POLYTOPE_PYRAMID; 4586 break; 4587 } 4588 } break; 4589 case 6: 4590 ct = DM_POLYTOPE_HEXAHEDRON; 4591 break; 4592 default: 4593 break; 4594 } 4595 break; 4596 default: 4597 break; 4598 } 4599 } else if (pheight > 0) { 4600 switch (coneSize) { 4601 case 2: 4602 ct = DM_POLYTOPE_SEGMENT; 4603 break; 4604 case 3: 4605 ct = DM_POLYTOPE_TRIANGLE; 4606 break; 4607 case 4: 4608 ct = DM_POLYTOPE_QUADRILATERAL; 4609 break; 4610 default: 4611 break; 4612 } 4613 } 4614 } 4615 *pt = ct; 4616 PetscFunctionReturn(PETSC_SUCCESS); 4617 } 4618 4619 /*@ 4620 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4621 4622 Collective 4623 4624 Input Parameter: 4625 . dm - The `DMPLEX` 4626 4627 Level: developer 4628 4629 Note: 4630 This function is normally called automatically when a cell type is requested. It creates an 4631 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4632 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4633 4634 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4635 4636 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4637 @*/ 4638 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4639 { 4640 DM_Plex *mesh; 4641 DMLabel ctLabel; 4642 PetscInt pStart, pEnd, p; 4643 4644 PetscFunctionBegin; 4645 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4646 mesh = (DM_Plex *)dm->data; 4647 PetscCall(DMCreateLabel(dm, "celltype")); 4648 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4649 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4650 PetscCall(PetscFree(mesh->cellTypes)); 4651 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4652 for (p = pStart; p < pEnd; ++p) { 4653 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4654 PetscInt pdepth; 4655 4656 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4657 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4658 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4659 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4660 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4661 } 4662 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4663 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4664 PetscFunctionReturn(PETSC_SUCCESS); 4665 } 4666 4667 /*@C 4668 DMPlexGetJoin - Get an array for the join of the set of points 4669 4670 Not Collective 4671 4672 Input Parameters: 4673 + dm - The `DMPLEX` object 4674 . numPoints - The number of input points for the join 4675 - points - The input points 4676 4677 Output Parameters: 4678 + numCoveredPoints - The number of points in the join 4679 - coveredPoints - The points in the join 4680 4681 Level: intermediate 4682 4683 Note: 4684 Currently, this is restricted to a single level join 4685 4686 Fortran Notes: 4687 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4688 4689 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4690 @*/ 4691 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4692 { 4693 DM_Plex *mesh = (DM_Plex *)dm->data; 4694 PetscInt *join[2]; 4695 PetscInt joinSize, i = 0; 4696 PetscInt dof, off, p, c, m; 4697 PetscInt maxSupportSize; 4698 4699 PetscFunctionBegin; 4700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4701 PetscAssertPointer(points, 3); 4702 PetscAssertPointer(numCoveredPoints, 4); 4703 PetscAssertPointer(coveredPoints, 5); 4704 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4705 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4706 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4707 /* Copy in support of first point */ 4708 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4709 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4710 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4711 /* Check each successive support */ 4712 for (p = 1; p < numPoints; ++p) { 4713 PetscInt newJoinSize = 0; 4714 4715 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4716 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4717 for (c = 0; c < dof; ++c) { 4718 const PetscInt point = mesh->supports[off + c]; 4719 4720 for (m = 0; m < joinSize; ++m) { 4721 if (point == join[i][m]) { 4722 join[1 - i][newJoinSize++] = point; 4723 break; 4724 } 4725 } 4726 } 4727 joinSize = newJoinSize; 4728 i = 1 - i; 4729 } 4730 *numCoveredPoints = joinSize; 4731 *coveredPoints = join[i]; 4732 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4733 PetscFunctionReturn(PETSC_SUCCESS); 4734 } 4735 4736 /*@C 4737 DMPlexRestoreJoin - Restore an array for the join of the set of points 4738 4739 Not Collective 4740 4741 Input Parameters: 4742 + dm - The `DMPLEX` object 4743 . numPoints - The number of input points for the join 4744 - points - The input points 4745 4746 Output Parameters: 4747 + numCoveredPoints - The number of points in the join 4748 - coveredPoints - The points in the join 4749 4750 Level: intermediate 4751 4752 Fortran Notes: 4753 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4754 4755 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4756 @*/ 4757 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4758 { 4759 PetscFunctionBegin; 4760 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4761 if (points) PetscAssertPointer(points, 3); 4762 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4763 PetscAssertPointer(coveredPoints, 5); 4764 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4765 if (numCoveredPoints) *numCoveredPoints = 0; 4766 PetscFunctionReturn(PETSC_SUCCESS); 4767 } 4768 4769 /*@C 4770 DMPlexGetFullJoin - Get an array for the join of the set of points 4771 4772 Not Collective 4773 4774 Input Parameters: 4775 + dm - The `DMPLEX` object 4776 . numPoints - The number of input points for the join 4777 - points - The input points 4778 4779 Output Parameters: 4780 + numCoveredPoints - The number of points in the join 4781 - coveredPoints - The points in the join 4782 4783 Level: intermediate 4784 4785 Fortran Notes: 4786 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4787 4788 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4789 @*/ 4790 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4791 { 4792 PetscInt *offsets, **closures; 4793 PetscInt *join[2]; 4794 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4795 PetscInt p, d, c, m, ms; 4796 4797 PetscFunctionBegin; 4798 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4799 PetscAssertPointer(points, 3); 4800 PetscAssertPointer(numCoveredPoints, 4); 4801 PetscAssertPointer(coveredPoints, 5); 4802 4803 PetscCall(DMPlexGetDepth(dm, &depth)); 4804 PetscCall(PetscCalloc1(numPoints, &closures)); 4805 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4806 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4807 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4808 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4809 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4810 4811 for (p = 0; p < numPoints; ++p) { 4812 PetscInt closureSize; 4813 4814 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4815 4816 offsets[p * (depth + 2) + 0] = 0; 4817 for (d = 0; d < depth + 1; ++d) { 4818 PetscInt pStart, pEnd, i; 4819 4820 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4821 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4822 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4823 offsets[p * (depth + 2) + d + 1] = i; 4824 break; 4825 } 4826 } 4827 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4828 } 4829 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); 4830 } 4831 for (d = 0; d < depth + 1; ++d) { 4832 PetscInt dof; 4833 4834 /* Copy in support of first point */ 4835 dof = offsets[d + 1] - offsets[d]; 4836 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4837 /* Check each successive cone */ 4838 for (p = 1; p < numPoints && joinSize; ++p) { 4839 PetscInt newJoinSize = 0; 4840 4841 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4842 for (c = 0; c < dof; ++c) { 4843 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4844 4845 for (m = 0; m < joinSize; ++m) { 4846 if (point == join[i][m]) { 4847 join[1 - i][newJoinSize++] = point; 4848 break; 4849 } 4850 } 4851 } 4852 joinSize = newJoinSize; 4853 i = 1 - i; 4854 } 4855 if (joinSize) break; 4856 } 4857 *numCoveredPoints = joinSize; 4858 *coveredPoints = join[i]; 4859 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4860 PetscCall(PetscFree(closures)); 4861 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4862 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4863 PetscFunctionReturn(PETSC_SUCCESS); 4864 } 4865 4866 /*@C 4867 DMPlexGetMeet - Get an array for the meet of the set of points 4868 4869 Not Collective 4870 4871 Input Parameters: 4872 + dm - The `DMPLEX` object 4873 . numPoints - The number of input points for the meet 4874 - points - The input points 4875 4876 Output Parameters: 4877 + numCoveringPoints - The number of points in the meet 4878 - coveringPoints - The points in the meet 4879 4880 Level: intermediate 4881 4882 Note: 4883 Currently, this is restricted to a single level meet 4884 4885 Fortran Notes: 4886 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4887 4888 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4889 @*/ 4890 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4891 { 4892 DM_Plex *mesh = (DM_Plex *)dm->data; 4893 PetscInt *meet[2]; 4894 PetscInt meetSize, i = 0; 4895 PetscInt dof, off, p, c, m; 4896 PetscInt maxConeSize; 4897 4898 PetscFunctionBegin; 4899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4900 PetscAssertPointer(points, 3); 4901 PetscAssertPointer(numCoveringPoints, 4); 4902 PetscAssertPointer(coveringPoints, 5); 4903 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4904 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4905 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4906 /* Copy in cone of first point */ 4907 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4908 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4909 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4910 /* Check each successive cone */ 4911 for (p = 1; p < numPoints; ++p) { 4912 PetscInt newMeetSize = 0; 4913 4914 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4915 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4916 for (c = 0; c < dof; ++c) { 4917 const PetscInt point = mesh->cones[off + c]; 4918 4919 for (m = 0; m < meetSize; ++m) { 4920 if (point == meet[i][m]) { 4921 meet[1 - i][newMeetSize++] = point; 4922 break; 4923 } 4924 } 4925 } 4926 meetSize = newMeetSize; 4927 i = 1 - i; 4928 } 4929 *numCoveringPoints = meetSize; 4930 *coveringPoints = meet[i]; 4931 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4932 PetscFunctionReturn(PETSC_SUCCESS); 4933 } 4934 4935 /*@C 4936 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4937 4938 Not Collective 4939 4940 Input Parameters: 4941 + dm - The `DMPLEX` object 4942 . numPoints - The number of input points for the meet 4943 - points - The input points 4944 4945 Output Parameters: 4946 + numCoveredPoints - The number of points in the meet 4947 - coveredPoints - The points in the meet 4948 4949 Level: intermediate 4950 4951 Fortran Notes: 4952 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4953 4954 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4955 @*/ 4956 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4957 { 4958 PetscFunctionBegin; 4959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4960 if (points) PetscAssertPointer(points, 3); 4961 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4962 PetscAssertPointer(coveredPoints, 5); 4963 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4964 if (numCoveredPoints) *numCoveredPoints = 0; 4965 PetscFunctionReturn(PETSC_SUCCESS); 4966 } 4967 4968 /*@C 4969 DMPlexGetFullMeet - Get an array for the meet of the set of points 4970 4971 Not Collective 4972 4973 Input Parameters: 4974 + dm - The `DMPLEX` object 4975 . numPoints - The number of input points for the meet 4976 - points - The input points 4977 4978 Output Parameters: 4979 + numCoveredPoints - The number of points in the meet 4980 - coveredPoints - The points in the meet 4981 4982 Level: intermediate 4983 4984 Fortran Notes: 4985 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4986 4987 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4988 @*/ 4989 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4990 { 4991 PetscInt *offsets, **closures; 4992 PetscInt *meet[2]; 4993 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4994 PetscInt p, h, c, m, mc; 4995 4996 PetscFunctionBegin; 4997 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4998 PetscAssertPointer(points, 3); 4999 PetscAssertPointer(numCoveredPoints, 4); 5000 PetscAssertPointer(coveredPoints, 5); 5001 5002 PetscCall(DMPlexGetDepth(dm, &height)); 5003 PetscCall(PetscMalloc1(numPoints, &closures)); 5004 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5005 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5006 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5007 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5008 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5009 5010 for (p = 0; p < numPoints; ++p) { 5011 PetscInt closureSize; 5012 5013 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5014 5015 offsets[p * (height + 2) + 0] = 0; 5016 for (h = 0; h < height + 1; ++h) { 5017 PetscInt pStart, pEnd, i; 5018 5019 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5020 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5021 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5022 offsets[p * (height + 2) + h + 1] = i; 5023 break; 5024 } 5025 } 5026 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5027 } 5028 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); 5029 } 5030 for (h = 0; h < height + 1; ++h) { 5031 PetscInt dof; 5032 5033 /* Copy in cone of first point */ 5034 dof = offsets[h + 1] - offsets[h]; 5035 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5036 /* Check each successive cone */ 5037 for (p = 1; p < numPoints && meetSize; ++p) { 5038 PetscInt newMeetSize = 0; 5039 5040 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5041 for (c = 0; c < dof; ++c) { 5042 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5043 5044 for (m = 0; m < meetSize; ++m) { 5045 if (point == meet[i][m]) { 5046 meet[1 - i][newMeetSize++] = point; 5047 break; 5048 } 5049 } 5050 } 5051 meetSize = newMeetSize; 5052 i = 1 - i; 5053 } 5054 if (meetSize) break; 5055 } 5056 *numCoveredPoints = meetSize; 5057 *coveredPoints = meet[i]; 5058 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5059 PetscCall(PetscFree(closures)); 5060 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5061 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5062 PetscFunctionReturn(PETSC_SUCCESS); 5063 } 5064 5065 /*@ 5066 DMPlexEqual - Determine if two `DM` have the same topology 5067 5068 Not Collective 5069 5070 Input Parameters: 5071 + dmA - A `DMPLEX` object 5072 - dmB - A `DMPLEX` object 5073 5074 Output Parameter: 5075 . equal - `PETSC_TRUE` if the topologies are identical 5076 5077 Level: intermediate 5078 5079 Note: 5080 We are not solving graph isomorphism, so we do not permute. 5081 5082 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5083 @*/ 5084 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5085 { 5086 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5087 5088 PetscFunctionBegin; 5089 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5090 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5091 PetscAssertPointer(equal, 3); 5092 5093 *equal = PETSC_FALSE; 5094 PetscCall(DMPlexGetDepth(dmA, &depth)); 5095 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5096 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5097 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5098 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5099 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5100 for (p = pStart; p < pEnd; ++p) { 5101 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5102 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5103 5104 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5105 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5106 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5107 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5108 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5109 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5110 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5111 for (c = 0; c < coneSize; ++c) { 5112 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5113 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5114 } 5115 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5116 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5117 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5118 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5119 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5120 for (s = 0; s < supportSize; ++s) { 5121 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5122 } 5123 } 5124 *equal = PETSC_TRUE; 5125 PetscFunctionReturn(PETSC_SUCCESS); 5126 } 5127 5128 /*@ 5129 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5130 5131 Not Collective 5132 5133 Input Parameters: 5134 + dm - The `DMPLEX` 5135 . cellDim - The cell dimension 5136 - numCorners - The number of vertices on a cell 5137 5138 Output Parameter: 5139 . numFaceVertices - The number of vertices on a face 5140 5141 Level: developer 5142 5143 Note: 5144 Of course this can only work for a restricted set of symmetric shapes 5145 5146 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5147 @*/ 5148 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5149 { 5150 MPI_Comm comm; 5151 5152 PetscFunctionBegin; 5153 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5154 PetscAssertPointer(numFaceVertices, 4); 5155 switch (cellDim) { 5156 case 0: 5157 *numFaceVertices = 0; 5158 break; 5159 case 1: 5160 *numFaceVertices = 1; 5161 break; 5162 case 2: 5163 switch (numCorners) { 5164 case 3: /* triangle */ 5165 *numFaceVertices = 2; /* Edge has 2 vertices */ 5166 break; 5167 case 4: /* quadrilateral */ 5168 *numFaceVertices = 2; /* Edge has 2 vertices */ 5169 break; 5170 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5171 *numFaceVertices = 3; /* Edge has 3 vertices */ 5172 break; 5173 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5174 *numFaceVertices = 3; /* Edge has 3 vertices */ 5175 break; 5176 default: 5177 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5178 } 5179 break; 5180 case 3: 5181 switch (numCorners) { 5182 case 4: /* tetradehdron */ 5183 *numFaceVertices = 3; /* Face has 3 vertices */ 5184 break; 5185 case 6: /* tet cohesive cells */ 5186 *numFaceVertices = 4; /* Face has 4 vertices */ 5187 break; 5188 case 8: /* hexahedron */ 5189 *numFaceVertices = 4; /* Face has 4 vertices */ 5190 break; 5191 case 9: /* tet cohesive Lagrange cells */ 5192 *numFaceVertices = 6; /* Face has 6 vertices */ 5193 break; 5194 case 10: /* quadratic tetrahedron */ 5195 *numFaceVertices = 6; /* Face has 6 vertices */ 5196 break; 5197 case 12: /* hex cohesive Lagrange cells */ 5198 *numFaceVertices = 6; /* Face has 6 vertices */ 5199 break; 5200 case 18: /* quadratic tet cohesive Lagrange cells */ 5201 *numFaceVertices = 6; /* Face has 6 vertices */ 5202 break; 5203 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5204 *numFaceVertices = 9; /* Face has 9 vertices */ 5205 break; 5206 default: 5207 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5208 } 5209 break; 5210 default: 5211 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5212 } 5213 PetscFunctionReturn(PETSC_SUCCESS); 5214 } 5215 5216 /*@ 5217 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5218 5219 Not Collective 5220 5221 Input Parameter: 5222 . dm - The `DMPLEX` object 5223 5224 Output Parameter: 5225 . depthLabel - The `DMLabel` recording point depth 5226 5227 Level: developer 5228 5229 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5230 @*/ 5231 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5232 { 5233 PetscFunctionBegin; 5234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5235 PetscAssertPointer(depthLabel, 2); 5236 *depthLabel = dm->depthLabel; 5237 PetscFunctionReturn(PETSC_SUCCESS); 5238 } 5239 5240 /*@ 5241 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5242 5243 Not Collective 5244 5245 Input Parameter: 5246 . dm - The `DMPLEX` object 5247 5248 Output Parameter: 5249 . depth - The number of strata (breadth first levels) in the DAG 5250 5251 Level: developer 5252 5253 Notes: 5254 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5255 5256 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5257 5258 An empty mesh gives -1. 5259 5260 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5261 @*/ 5262 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5263 { 5264 DM_Plex *mesh = (DM_Plex *)dm->data; 5265 DMLabel label; 5266 PetscInt d = -1; 5267 5268 PetscFunctionBegin; 5269 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5270 PetscAssertPointer(depth, 2); 5271 if (mesh->tr) { 5272 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5273 } else { 5274 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5275 // Allow missing depths 5276 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5277 *depth = d; 5278 } 5279 PetscFunctionReturn(PETSC_SUCCESS); 5280 } 5281 5282 /*@ 5283 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5284 5285 Not Collective 5286 5287 Input Parameters: 5288 + dm - The `DMPLEX` object 5289 - depth - The requested depth 5290 5291 Output Parameters: 5292 + start - The first point at this `depth` 5293 - end - One beyond the last point at this `depth` 5294 5295 Level: developer 5296 5297 Notes: 5298 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5299 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5300 higher dimension, e.g., "edges". 5301 5302 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5303 @*/ 5304 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5305 { 5306 DM_Plex *mesh = (DM_Plex *)dm->data; 5307 DMLabel label; 5308 PetscInt pStart, pEnd; 5309 5310 PetscFunctionBegin; 5311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5312 if (start) { 5313 PetscAssertPointer(start, 3); 5314 *start = 0; 5315 } 5316 if (end) { 5317 PetscAssertPointer(end, 4); 5318 *end = 0; 5319 } 5320 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5321 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5322 if (depth < 0) { 5323 if (start) *start = pStart; 5324 if (end) *end = pEnd; 5325 PetscFunctionReturn(PETSC_SUCCESS); 5326 } 5327 if (mesh->tr) { 5328 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5329 } else { 5330 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5331 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5332 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5333 } 5334 PetscFunctionReturn(PETSC_SUCCESS); 5335 } 5336 5337 /*@ 5338 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5339 5340 Not Collective 5341 5342 Input Parameters: 5343 + dm - The `DMPLEX` object 5344 - height - The requested height 5345 5346 Output Parameters: 5347 + start - The first point at this `height` 5348 - end - One beyond the last point at this `height` 5349 5350 Level: developer 5351 5352 Notes: 5353 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5354 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5355 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5356 5357 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5358 @*/ 5359 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5360 { 5361 DMLabel label; 5362 PetscInt depth, pStart, pEnd; 5363 5364 PetscFunctionBegin; 5365 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5366 if (start) { 5367 PetscAssertPointer(start, 3); 5368 *start = 0; 5369 } 5370 if (end) { 5371 PetscAssertPointer(end, 4); 5372 *end = 0; 5373 } 5374 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5375 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5376 if (height < 0) { 5377 if (start) *start = pStart; 5378 if (end) *end = pEnd; 5379 PetscFunctionReturn(PETSC_SUCCESS); 5380 } 5381 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5382 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5383 else PetscCall(DMGetDimension(dm, &depth)); 5384 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5385 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5386 PetscFunctionReturn(PETSC_SUCCESS); 5387 } 5388 5389 /*@ 5390 DMPlexGetPointDepth - Get the `depth` of a given point 5391 5392 Not Collective 5393 5394 Input Parameters: 5395 + dm - The `DMPLEX` object 5396 - point - The point 5397 5398 Output Parameter: 5399 . depth - The depth of the `point` 5400 5401 Level: intermediate 5402 5403 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5404 @*/ 5405 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5406 { 5407 PetscFunctionBegin; 5408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5409 PetscAssertPointer(depth, 3); 5410 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5411 PetscFunctionReturn(PETSC_SUCCESS); 5412 } 5413 5414 /*@ 5415 DMPlexGetPointHeight - Get the `height` of a given point 5416 5417 Not Collective 5418 5419 Input Parameters: 5420 + dm - The `DMPLEX` object 5421 - point - The point 5422 5423 Output Parameter: 5424 . height - The height of the `point` 5425 5426 Level: intermediate 5427 5428 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5429 @*/ 5430 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5431 { 5432 PetscInt n, pDepth; 5433 5434 PetscFunctionBegin; 5435 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5436 PetscAssertPointer(height, 3); 5437 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5438 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5439 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5440 PetscFunctionReturn(PETSC_SUCCESS); 5441 } 5442 5443 /*@ 5444 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5445 5446 Not Collective 5447 5448 Input Parameter: 5449 . dm - The `DMPLEX` object 5450 5451 Output Parameter: 5452 . celltypeLabel - The `DMLabel` recording cell polytope type 5453 5454 Level: developer 5455 5456 Note: 5457 This function will trigger automatica computation of cell types. This can be disabled by calling 5458 `DMCreateLabel`(dm, "celltype") beforehand. 5459 5460 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5461 @*/ 5462 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5463 { 5464 PetscFunctionBegin; 5465 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5466 PetscAssertPointer(celltypeLabel, 2); 5467 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5468 *celltypeLabel = dm->celltypeLabel; 5469 PetscFunctionReturn(PETSC_SUCCESS); 5470 } 5471 5472 /*@ 5473 DMPlexGetCellType - Get the polytope type of a given cell 5474 5475 Not Collective 5476 5477 Input Parameters: 5478 + dm - The `DMPLEX` object 5479 - cell - The cell 5480 5481 Output Parameter: 5482 . celltype - The polytope type of the cell 5483 5484 Level: intermediate 5485 5486 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5487 @*/ 5488 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5489 { 5490 DM_Plex *mesh = (DM_Plex *)dm->data; 5491 DMLabel label; 5492 PetscInt ct; 5493 5494 PetscFunctionBegin; 5495 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5496 PetscAssertPointer(celltype, 3); 5497 if (mesh->tr) { 5498 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5499 } else { 5500 PetscInt pStart, pEnd; 5501 5502 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5503 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5504 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5505 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5506 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5507 for (PetscInt p = pStart; p < pEnd; p++) { 5508 PetscCall(DMLabelGetValue(label, p, &ct)); 5509 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5510 } 5511 } 5512 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5513 if (PetscDefined(USE_DEBUG)) { 5514 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5515 PetscCall(DMLabelGetValue(label, cell, &ct)); 5516 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5517 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5518 } 5519 } 5520 PetscFunctionReturn(PETSC_SUCCESS); 5521 } 5522 5523 /*@ 5524 DMPlexSetCellType - Set the polytope type of a given cell 5525 5526 Not Collective 5527 5528 Input Parameters: 5529 + dm - The `DMPLEX` object 5530 . cell - The cell 5531 - celltype - The polytope type of the cell 5532 5533 Level: advanced 5534 5535 Note: 5536 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5537 is executed. This function will override the computed type. However, if automatic classification will not succeed 5538 and a user wants to manually specify all types, the classification must be disabled by calling 5539 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5540 5541 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5542 @*/ 5543 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5544 { 5545 DM_Plex *mesh = (DM_Plex *)dm->data; 5546 DMLabel label; 5547 PetscInt pStart, pEnd; 5548 5549 PetscFunctionBegin; 5550 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5551 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5552 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5553 PetscCall(DMLabelSetValue(label, cell, celltype)); 5554 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5555 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5556 PetscFunctionReturn(PETSC_SUCCESS); 5557 } 5558 5559 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5560 { 5561 PetscSection section; 5562 PetscInt maxHeight; 5563 const char *prefix; 5564 5565 PetscFunctionBegin; 5566 PetscCall(DMClone(dm, cdm)); 5567 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5568 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5569 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5570 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5571 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5572 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5573 PetscCall(DMSetLocalSection(*cdm, section)); 5574 PetscCall(PetscSectionDestroy(§ion)); 5575 5576 PetscCall(DMSetNumFields(*cdm, 1)); 5577 PetscCall(DMCreateDS(*cdm)); 5578 (*cdm)->cloneOpts = PETSC_TRUE; 5579 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5580 PetscFunctionReturn(PETSC_SUCCESS); 5581 } 5582 5583 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5584 { 5585 Vec coordsLocal, cellCoordsLocal; 5586 DM coordsDM, cellCoordsDM; 5587 5588 PetscFunctionBegin; 5589 *field = NULL; 5590 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5591 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5592 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5593 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5594 if (coordsLocal && coordsDM) { 5595 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5596 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5597 } 5598 PetscFunctionReturn(PETSC_SUCCESS); 5599 } 5600 5601 /*@ 5602 DMPlexGetConeSection - Return a section which describes the layout of cone data 5603 5604 Not Collective 5605 5606 Input Parameter: 5607 . dm - The `DMPLEX` object 5608 5609 Output Parameter: 5610 . section - The `PetscSection` object 5611 5612 Level: developer 5613 5614 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5615 @*/ 5616 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5617 { 5618 DM_Plex *mesh = (DM_Plex *)dm->data; 5619 5620 PetscFunctionBegin; 5621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5622 if (section) *section = mesh->coneSection; 5623 PetscFunctionReturn(PETSC_SUCCESS); 5624 } 5625 5626 /*@ 5627 DMPlexGetSupportSection - Return a section which describes the layout of support data 5628 5629 Not Collective 5630 5631 Input Parameter: 5632 . dm - The `DMPLEX` object 5633 5634 Output Parameter: 5635 . section - The `PetscSection` object 5636 5637 Level: developer 5638 5639 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5640 @*/ 5641 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5642 { 5643 DM_Plex *mesh = (DM_Plex *)dm->data; 5644 5645 PetscFunctionBegin; 5646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5647 if (section) *section = mesh->supportSection; 5648 PetscFunctionReturn(PETSC_SUCCESS); 5649 } 5650 5651 /*@C 5652 DMPlexGetCones - Return cone data 5653 5654 Not Collective 5655 5656 Input Parameter: 5657 . dm - The `DMPLEX` object 5658 5659 Output Parameter: 5660 . cones - The cone for each point 5661 5662 Level: developer 5663 5664 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5665 @*/ 5666 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5667 { 5668 DM_Plex *mesh = (DM_Plex *)dm->data; 5669 5670 PetscFunctionBegin; 5671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5672 if (cones) *cones = mesh->cones; 5673 PetscFunctionReturn(PETSC_SUCCESS); 5674 } 5675 5676 /*@C 5677 DMPlexGetConeOrientations - Return cone orientation data 5678 5679 Not Collective 5680 5681 Input Parameter: 5682 . dm - The `DMPLEX` object 5683 5684 Output Parameter: 5685 . coneOrientations - The array of cone orientations for all points 5686 5687 Level: developer 5688 5689 Notes: 5690 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5691 5692 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5693 5694 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5695 @*/ 5696 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5697 { 5698 DM_Plex *mesh = (DM_Plex *)dm->data; 5699 5700 PetscFunctionBegin; 5701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5702 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5703 PetscFunctionReturn(PETSC_SUCCESS); 5704 } 5705 5706 /******************************** FEM Support **********************************/ 5707 5708 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5709 { 5710 PetscInt depth; 5711 5712 PetscFunctionBegin; 5713 PetscCall(DMPlexGetDepth(plex, &depth)); 5714 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5715 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5716 PetscFunctionReturn(PETSC_SUCCESS); 5717 } 5718 5719 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5720 { 5721 PetscInt depth; 5722 5723 PetscFunctionBegin; 5724 PetscCall(DMPlexGetDepth(plex, &depth)); 5725 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5726 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5727 PetscFunctionReturn(PETSC_SUCCESS); 5728 } 5729 5730 /* 5731 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5732 representing a line in the section. 5733 */ 5734 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5735 { 5736 PetscObject obj; 5737 PetscClassId id; 5738 PetscFE fe = NULL; 5739 5740 PetscFunctionBeginHot; 5741 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5742 PetscCall(DMGetField(dm, field, NULL, &obj)); 5743 PetscCall(PetscObjectGetClassId(obj, &id)); 5744 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5745 5746 if (!fe) { 5747 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5748 /* An order k SEM disc has k-1 dofs on an edge */ 5749 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5750 *k = *k / *Nc + 1; 5751 } else { 5752 PetscInt dual_space_size, dim; 5753 PetscDualSpace dsp; 5754 5755 PetscCall(DMGetDimension(dm, &dim)); 5756 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5757 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5758 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5759 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5760 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5761 } 5762 PetscFunctionReturn(PETSC_SUCCESS); 5763 } 5764 5765 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5766 { 5767 PetscFunctionBeginHot; 5768 if (tensor) { 5769 *dof = PetscPowInt(k + 1, dim); 5770 } else { 5771 switch (dim) { 5772 case 1: 5773 *dof = k + 1; 5774 break; 5775 case 2: 5776 *dof = ((k + 1) * (k + 2)) / 2; 5777 break; 5778 case 3: 5779 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5780 break; 5781 default: 5782 *dof = 0; 5783 } 5784 } 5785 PetscFunctionReturn(PETSC_SUCCESS); 5786 } 5787 5788 /*@ 5789 5790 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5791 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5792 section provided (or the section of the `DM`). 5793 5794 Input Parameters: 5795 + dm - The `DM` 5796 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5797 - section - The `PetscSection` to reorder, or `NULL` for the default section 5798 5799 Example: 5800 A typical interpolated single-quad mesh might order points as 5801 .vb 5802 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5803 5804 v4 -- e6 -- v3 5805 | | 5806 e7 c0 e8 5807 | | 5808 v1 -- e5 -- v2 5809 .ve 5810 5811 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5812 dofs in the order of points, e.g., 5813 .vb 5814 c0 -> [0,1,2,3] 5815 v1 -> [4] 5816 ... 5817 e5 -> [8, 9] 5818 .ve 5819 5820 which corresponds to the dofs 5821 .vb 5822 6 10 11 7 5823 13 2 3 15 5824 12 0 1 14 5825 4 8 9 5 5826 .ve 5827 5828 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5829 .vb 5830 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5831 .ve 5832 5833 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5834 .vb 5835 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5836 .ve 5837 5838 Level: developer 5839 5840 Notes: 5841 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5842 degree of the basis. 5843 5844 This is required to run with libCEED. 5845 5846 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5847 @*/ 5848 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5849 { 5850 DMLabel label; 5851 PetscInt dim, depth = -1, eStart = -1, Nf; 5852 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5853 5854 PetscFunctionBegin; 5855 PetscCall(DMGetDimension(dm, &dim)); 5856 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5857 if (point < 0) { 5858 PetscInt sStart, sEnd; 5859 5860 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5861 point = sEnd - sStart ? sStart : point; 5862 } 5863 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5864 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5865 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5866 if (depth == 1) { 5867 eStart = point; 5868 } else if (depth == dim) { 5869 const PetscInt *cone; 5870 5871 PetscCall(DMPlexGetCone(dm, point, &cone)); 5872 if (dim == 2) eStart = cone[0]; 5873 else if (dim == 3) { 5874 const PetscInt *cone2; 5875 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5876 eStart = cone2[0]; 5877 } 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); 5878 } 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); 5879 5880 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5881 for (PetscInt d = 1; d <= dim; d++) { 5882 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5883 PetscInt *perm; 5884 5885 for (f = 0; f < Nf; ++f) { 5886 PetscInt dof; 5887 5888 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5889 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5890 if (!continuous && d < dim) continue; 5891 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5892 size += dof * Nc; 5893 } 5894 PetscCall(PetscMalloc1(size, &perm)); 5895 for (f = 0; f < Nf; ++f) { 5896 switch (d) { 5897 case 1: 5898 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5899 if (!continuous && d < dim) continue; 5900 /* 5901 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5902 We want [ vtx0; edge of length k-1; vtx1 ] 5903 */ 5904 if (continuous) { 5905 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5906 for (i = 0; i < k - 1; i++) 5907 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5908 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5909 foffset = offset; 5910 } else { 5911 PetscInt dof; 5912 5913 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5914 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5915 foffset = offset; 5916 } 5917 break; 5918 case 2: 5919 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5920 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5921 if (!continuous && d < dim) continue; 5922 /* The SEM order is 5923 5924 v_lb, {e_b}, v_rb, 5925 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5926 v_lt, reverse {e_t}, v_rt 5927 */ 5928 if (continuous) { 5929 const PetscInt of = 0; 5930 const PetscInt oeb = of + PetscSqr(k - 1); 5931 const PetscInt oer = oeb + (k - 1); 5932 const PetscInt oet = oer + (k - 1); 5933 const PetscInt oel = oet + (k - 1); 5934 const PetscInt ovlb = oel + (k - 1); 5935 const PetscInt ovrb = ovlb + 1; 5936 const PetscInt ovrt = ovrb + 1; 5937 const PetscInt ovlt = ovrt + 1; 5938 PetscInt o; 5939 5940 /* bottom */ 5941 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5942 for (o = oeb; o < oer; ++o) 5943 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5944 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5945 /* middle */ 5946 for (i = 0; i < k - 1; ++i) { 5947 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5948 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5949 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5950 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5951 } 5952 /* top */ 5953 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5954 for (o = oel - 1; o >= oet; --o) 5955 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5956 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5957 foffset = offset; 5958 } else { 5959 PetscInt dof; 5960 5961 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5962 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5963 foffset = offset; 5964 } 5965 break; 5966 case 3: 5967 /* The original hex closure is 5968 5969 {c, 5970 f_b, f_t, f_f, f_b, f_r, f_l, 5971 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5972 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5973 */ 5974 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5975 if (!continuous && d < dim) continue; 5976 /* The SEM order is 5977 Bottom Slice 5978 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5979 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5980 v_blb, {e_bb}, v_brb, 5981 5982 Middle Slice (j) 5983 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5984 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5985 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5986 5987 Top Slice 5988 v_tlf, {e_tf}, v_trf, 5989 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5990 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5991 */ 5992 if (continuous) { 5993 const PetscInt oc = 0; 5994 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5995 const PetscInt oft = ofb + PetscSqr(k - 1); 5996 const PetscInt off = oft + PetscSqr(k - 1); 5997 const PetscInt ofk = off + PetscSqr(k - 1); 5998 const PetscInt ofr = ofk + PetscSqr(k - 1); 5999 const PetscInt ofl = ofr + PetscSqr(k - 1); 6000 const PetscInt oebl = ofl + PetscSqr(k - 1); 6001 const PetscInt oebb = oebl + (k - 1); 6002 const PetscInt oebr = oebb + (k - 1); 6003 const PetscInt oebf = oebr + (k - 1); 6004 const PetscInt oetf = oebf + (k - 1); 6005 const PetscInt oetr = oetf + (k - 1); 6006 const PetscInt oetb = oetr + (k - 1); 6007 const PetscInt oetl = oetb + (k - 1); 6008 const PetscInt oerf = oetl + (k - 1); 6009 const PetscInt oelf = oerf + (k - 1); 6010 const PetscInt oelb = oelf + (k - 1); 6011 const PetscInt oerb = oelb + (k - 1); 6012 const PetscInt ovblf = oerb + (k - 1); 6013 const PetscInt ovblb = ovblf + 1; 6014 const PetscInt ovbrb = ovblb + 1; 6015 const PetscInt ovbrf = ovbrb + 1; 6016 const PetscInt ovtlf = ovbrf + 1; 6017 const PetscInt ovtrf = ovtlf + 1; 6018 const PetscInt ovtrb = ovtrf + 1; 6019 const PetscInt ovtlb = ovtrb + 1; 6020 PetscInt o, n; 6021 6022 /* Bottom Slice */ 6023 /* bottom */ 6024 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6025 for (o = oetf - 1; o >= oebf; --o) 6026 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6027 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6028 /* middle */ 6029 for (i = 0; i < k - 1; ++i) { 6030 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6031 for (n = 0; n < k - 1; ++n) { 6032 o = ofb + n * (k - 1) + i; 6033 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6034 } 6035 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6036 } 6037 /* top */ 6038 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6039 for (o = oebb; o < oebr; ++o) 6040 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6041 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6042 6043 /* Middle Slice */ 6044 for (j = 0; j < k - 1; ++j) { 6045 /* bottom */ 6046 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6047 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6048 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6049 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6050 /* middle */ 6051 for (i = 0; i < k - 1; ++i) { 6052 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6053 for (n = 0; n < k - 1; ++n) 6054 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6055 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6056 } 6057 /* top */ 6058 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6059 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6060 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6061 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6062 } 6063 6064 /* Top Slice */ 6065 /* bottom */ 6066 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6067 for (o = oetf; o < oetr; ++o) 6068 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6069 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6070 /* middle */ 6071 for (i = 0; i < k - 1; ++i) { 6072 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6073 for (n = 0; n < k - 1; ++n) 6074 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6075 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6076 } 6077 /* top */ 6078 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6079 for (o = oetl - 1; o >= oetb; --o) 6080 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6081 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6082 6083 foffset = offset; 6084 } else { 6085 PetscInt dof; 6086 6087 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6088 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6089 foffset = offset; 6090 } 6091 break; 6092 default: 6093 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6094 } 6095 } 6096 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6097 /* Check permutation */ 6098 { 6099 PetscInt *check; 6100 6101 PetscCall(PetscMalloc1(size, &check)); 6102 for (i = 0; i < size; ++i) { 6103 check[i] = -1; 6104 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6105 } 6106 for (i = 0; i < size; ++i) check[perm[i]] = i; 6107 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6108 PetscCall(PetscFree(check)); 6109 } 6110 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6111 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6112 PetscInt *loc_perm; 6113 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6114 for (PetscInt i = 0; i < size; i++) { 6115 loc_perm[i] = perm[i]; 6116 loc_perm[size + i] = size + perm[i]; 6117 } 6118 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6119 } 6120 } 6121 PetscFunctionReturn(PETSC_SUCCESS); 6122 } 6123 6124 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6125 { 6126 PetscDS prob; 6127 PetscInt depth, Nf, h; 6128 DMLabel label; 6129 6130 PetscFunctionBeginHot; 6131 PetscCall(DMGetDS(dm, &prob)); 6132 Nf = prob->Nf; 6133 label = dm->depthLabel; 6134 *dspace = NULL; 6135 if (field < Nf) { 6136 PetscObject disc = prob->disc[field]; 6137 6138 if (disc->classid == PETSCFE_CLASSID) { 6139 PetscDualSpace dsp; 6140 6141 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6142 PetscCall(DMLabelGetNumValues(label, &depth)); 6143 PetscCall(DMLabelGetValue(label, point, &h)); 6144 h = depth - 1 - h; 6145 if (h) { 6146 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6147 } else { 6148 *dspace = dsp; 6149 } 6150 } 6151 } 6152 PetscFunctionReturn(PETSC_SUCCESS); 6153 } 6154 6155 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6156 { 6157 PetscScalar *array; 6158 const PetscScalar *vArray; 6159 const PetscInt *cone, *coneO; 6160 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6161 6162 PetscFunctionBeginHot; 6163 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6164 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6165 PetscCall(DMPlexGetCone(dm, point, &cone)); 6166 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6167 if (!values || !*values) { 6168 if ((point >= pStart) && (point < pEnd)) { 6169 PetscInt dof; 6170 6171 PetscCall(PetscSectionGetDof(section, point, &dof)); 6172 size += dof; 6173 } 6174 for (p = 0; p < numPoints; ++p) { 6175 const PetscInt cp = cone[p]; 6176 PetscInt dof; 6177 6178 if ((cp < pStart) || (cp >= pEnd)) continue; 6179 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6180 size += dof; 6181 } 6182 if (!values) { 6183 if (csize) *csize = size; 6184 PetscFunctionReturn(PETSC_SUCCESS); 6185 } 6186 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6187 } else { 6188 array = *values; 6189 } 6190 size = 0; 6191 PetscCall(VecGetArrayRead(v, &vArray)); 6192 if ((point >= pStart) && (point < pEnd)) { 6193 PetscInt dof, off, d; 6194 const PetscScalar *varr; 6195 6196 PetscCall(PetscSectionGetDof(section, point, &dof)); 6197 PetscCall(PetscSectionGetOffset(section, point, &off)); 6198 varr = PetscSafePointerPlusOffset(vArray, off); 6199 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6200 size += dof; 6201 } 6202 for (p = 0; p < numPoints; ++p) { 6203 const PetscInt cp = cone[p]; 6204 PetscInt o = coneO[p]; 6205 PetscInt dof, off, d; 6206 const PetscScalar *varr; 6207 6208 if ((cp < pStart) || (cp >= pEnd)) continue; 6209 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6210 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6211 varr = PetscSafePointerPlusOffset(vArray, off); 6212 if (o >= 0) { 6213 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6214 } else { 6215 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6216 } 6217 size += dof; 6218 } 6219 PetscCall(VecRestoreArrayRead(v, &vArray)); 6220 if (!*values) { 6221 if (csize) *csize = size; 6222 *values = array; 6223 } else { 6224 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6225 *csize = size; 6226 } 6227 PetscFunctionReturn(PETSC_SUCCESS); 6228 } 6229 6230 /* Compress out points not in the section */ 6231 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6232 { 6233 const PetscInt np = *numPoints; 6234 PetscInt pStart, pEnd, p, q; 6235 6236 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6237 for (p = 0, q = 0; p < np; ++p) { 6238 const PetscInt r = points[p * 2]; 6239 if ((r >= pStart) && (r < pEnd)) { 6240 points[q * 2] = r; 6241 points[q * 2 + 1] = points[p * 2 + 1]; 6242 ++q; 6243 } 6244 } 6245 *numPoints = q; 6246 return PETSC_SUCCESS; 6247 } 6248 6249 /* Compressed closure does not apply closure permutation */ 6250 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6251 { 6252 const PetscInt *cla = NULL; 6253 PetscInt np, *pts = NULL; 6254 6255 PetscFunctionBeginHot; 6256 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6257 if (!ornt && *clPoints) { 6258 PetscInt dof, off; 6259 6260 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6261 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6262 PetscCall(ISGetIndices(*clPoints, &cla)); 6263 np = dof / 2; 6264 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6265 } else { 6266 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6267 PetscCall(CompressPoints_Private(section, &np, pts)); 6268 } 6269 *numPoints = np; 6270 *points = pts; 6271 *clp = cla; 6272 PetscFunctionReturn(PETSC_SUCCESS); 6273 } 6274 6275 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6276 { 6277 PetscFunctionBeginHot; 6278 if (!*clPoints) { 6279 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6280 } else { 6281 PetscCall(ISRestoreIndices(*clPoints, clp)); 6282 } 6283 *numPoints = 0; 6284 *points = NULL; 6285 *clSec = NULL; 6286 *clPoints = NULL; 6287 *clp = NULL; 6288 PetscFunctionReturn(PETSC_SUCCESS); 6289 } 6290 6291 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6292 { 6293 PetscInt offset = 0, p; 6294 const PetscInt **perms = NULL; 6295 const PetscScalar **flips = NULL; 6296 6297 PetscFunctionBeginHot; 6298 *size = 0; 6299 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6300 for (p = 0; p < numPoints; p++) { 6301 const PetscInt point = points[2 * p]; 6302 const PetscInt *perm = perms ? perms[p] : NULL; 6303 const PetscScalar *flip = flips ? flips[p] : NULL; 6304 PetscInt dof, off, d; 6305 const PetscScalar *varr; 6306 6307 PetscCall(PetscSectionGetDof(section, point, &dof)); 6308 PetscCall(PetscSectionGetOffset(section, point, &off)); 6309 varr = PetscSafePointerPlusOffset(vArray, off); 6310 if (clperm) { 6311 if (perm) { 6312 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6313 } else { 6314 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6315 } 6316 if (flip) { 6317 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6318 } 6319 } else { 6320 if (perm) { 6321 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6322 } else { 6323 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6324 } 6325 if (flip) { 6326 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6327 } 6328 } 6329 offset += dof; 6330 } 6331 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6332 *size = offset; 6333 PetscFunctionReturn(PETSC_SUCCESS); 6334 } 6335 6336 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[]) 6337 { 6338 PetscInt offset = 0, f; 6339 6340 PetscFunctionBeginHot; 6341 *size = 0; 6342 for (f = 0; f < numFields; ++f) { 6343 PetscInt p; 6344 const PetscInt **perms = NULL; 6345 const PetscScalar **flips = NULL; 6346 6347 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6348 for (p = 0; p < numPoints; p++) { 6349 const PetscInt point = points[2 * p]; 6350 PetscInt fdof, foff, b; 6351 const PetscScalar *varr; 6352 const PetscInt *perm = perms ? perms[p] : NULL; 6353 const PetscScalar *flip = flips ? flips[p] : NULL; 6354 6355 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6356 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6357 varr = &vArray[foff]; 6358 if (clperm) { 6359 if (perm) { 6360 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6361 } else { 6362 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6363 } 6364 if (flip) { 6365 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6366 } 6367 } else { 6368 if (perm) { 6369 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6370 } else { 6371 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6372 } 6373 if (flip) { 6374 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6375 } 6376 } 6377 offset += fdof; 6378 } 6379 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6380 } 6381 *size = offset; 6382 PetscFunctionReturn(PETSC_SUCCESS); 6383 } 6384 6385 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6386 { 6387 PetscSection clSection; 6388 IS clPoints; 6389 PetscInt *points = NULL; 6390 const PetscInt *clp, *perm = NULL; 6391 PetscInt depth, numFields, numPoints, asize; 6392 6393 PetscFunctionBeginHot; 6394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6395 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6396 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6397 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6398 PetscCall(DMPlexGetDepth(dm, &depth)); 6399 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6400 if (depth == 1 && numFields < 2) { 6401 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6402 PetscFunctionReturn(PETSC_SUCCESS); 6403 } 6404 /* Get points */ 6405 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6406 /* Get sizes */ 6407 asize = 0; 6408 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6409 PetscInt dof; 6410 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6411 asize += dof; 6412 } 6413 if (values) { 6414 const PetscScalar *vArray; 6415 PetscInt size; 6416 6417 if (*values) { 6418 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); 6419 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6420 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6421 PetscCall(VecGetArrayRead(v, &vArray)); 6422 /* Get values */ 6423 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6424 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6425 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6426 /* Cleanup array */ 6427 PetscCall(VecRestoreArrayRead(v, &vArray)); 6428 } 6429 if (csize) *csize = asize; 6430 /* Cleanup points */ 6431 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6432 PetscFunctionReturn(PETSC_SUCCESS); 6433 } 6434 6435 /*@C 6436 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6437 6438 Not collective 6439 6440 Input Parameters: 6441 + dm - The `DM` 6442 . section - The section describing the layout in `v`, or `NULL` to use the default section 6443 . v - The local vector 6444 - point - The point in the `DM` 6445 6446 Input/Output Parameters: 6447 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6448 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6449 if the user provided `NULL`, it is a borrowed array and should not be freed 6450 6451 Level: intermediate 6452 6453 Notes: 6454 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6455 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6456 assembly function, and a user may already have allocated storage for this operation. 6457 6458 A typical use could be 6459 .vb 6460 values = NULL; 6461 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6462 for (cl = 0; cl < clSize; ++cl) { 6463 <Compute on closure> 6464 } 6465 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6466 .ve 6467 or 6468 .vb 6469 PetscMalloc1(clMaxSize, &values); 6470 for (p = pStart; p < pEnd; ++p) { 6471 clSize = clMaxSize; 6472 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6473 for (cl = 0; cl < clSize; ++cl) { 6474 <Compute on closure> 6475 } 6476 } 6477 PetscFree(values); 6478 .ve 6479 6480 Fortran Notes: 6481 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6482 6483 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6484 @*/ 6485 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6486 { 6487 PetscFunctionBeginHot; 6488 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6489 PetscFunctionReturn(PETSC_SUCCESS); 6490 } 6491 6492 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6493 { 6494 DMLabel depthLabel; 6495 PetscSection clSection; 6496 IS clPoints; 6497 PetscScalar *array; 6498 const PetscScalar *vArray; 6499 PetscInt *points = NULL; 6500 const PetscInt *clp, *perm = NULL; 6501 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6502 6503 PetscFunctionBeginHot; 6504 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6505 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6506 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6507 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6508 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6509 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6510 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6511 if (mdepth == 1 && numFields < 2) { 6512 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6513 PetscFunctionReturn(PETSC_SUCCESS); 6514 } 6515 /* Get points */ 6516 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6517 for (clsize = 0, p = 0; p < Np; p++) { 6518 PetscInt dof; 6519 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6520 clsize += dof; 6521 } 6522 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6523 /* Filter points */ 6524 for (p = 0; p < numPoints * 2; p += 2) { 6525 PetscInt dep; 6526 6527 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6528 if (dep != depth) continue; 6529 points[Np * 2 + 0] = points[p]; 6530 points[Np * 2 + 1] = points[p + 1]; 6531 ++Np; 6532 } 6533 /* Get array */ 6534 if (!values || !*values) { 6535 PetscInt asize = 0, dof; 6536 6537 for (p = 0; p < Np * 2; p += 2) { 6538 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6539 asize += dof; 6540 } 6541 if (!values) { 6542 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6543 if (csize) *csize = asize; 6544 PetscFunctionReturn(PETSC_SUCCESS); 6545 } 6546 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6547 } else { 6548 array = *values; 6549 } 6550 PetscCall(VecGetArrayRead(v, &vArray)); 6551 /* Get values */ 6552 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6553 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6554 /* Cleanup points */ 6555 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6556 /* Cleanup array */ 6557 PetscCall(VecRestoreArrayRead(v, &vArray)); 6558 if (!*values) { 6559 if (csize) *csize = size; 6560 *values = array; 6561 } else { 6562 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6563 *csize = size; 6564 } 6565 PetscFunctionReturn(PETSC_SUCCESS); 6566 } 6567 6568 /*@C 6569 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6570 6571 Not collective 6572 6573 Input Parameters: 6574 + dm - The `DM` 6575 . section - The section describing the layout in `v`, or `NULL` to use the default section 6576 . v - The local vector 6577 . point - The point in the `DM` 6578 . csize - The number of values in the closure, or `NULL` 6579 - values - The array of values, which is a borrowed array and should not be freed 6580 6581 Level: intermediate 6582 6583 Note: 6584 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6585 6586 Fortran Notes: 6587 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6588 6589 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6590 @*/ 6591 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6592 { 6593 PetscInt size = 0; 6594 6595 PetscFunctionBegin; 6596 /* Should work without recalculating size */ 6597 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6598 *values = NULL; 6599 PetscFunctionReturn(PETSC_SUCCESS); 6600 } 6601 6602 static inline void add(PetscScalar *x, PetscScalar y) 6603 { 6604 *x += y; 6605 } 6606 static inline void insert(PetscScalar *x, PetscScalar y) 6607 { 6608 *x = y; 6609 } 6610 6611 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[]) 6612 { 6613 PetscInt cdof; /* The number of constraints on this point */ 6614 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6615 PetscScalar *a; 6616 PetscInt off, cind = 0, k; 6617 6618 PetscFunctionBegin; 6619 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6620 PetscCall(PetscSectionGetOffset(section, point, &off)); 6621 a = &array[off]; 6622 if (!cdof || setBC) { 6623 if (clperm) { 6624 if (perm) { 6625 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6626 } else { 6627 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6628 } 6629 } else { 6630 if (perm) { 6631 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6632 } else { 6633 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6634 } 6635 } 6636 } else { 6637 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6638 if (clperm) { 6639 if (perm) { 6640 for (k = 0; k < dof; ++k) { 6641 if ((cind < cdof) && (k == cdofs[cind])) { 6642 ++cind; 6643 continue; 6644 } 6645 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6646 } 6647 } else { 6648 for (k = 0; k < dof; ++k) { 6649 if ((cind < cdof) && (k == cdofs[cind])) { 6650 ++cind; 6651 continue; 6652 } 6653 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6654 } 6655 } 6656 } else { 6657 if (perm) { 6658 for (k = 0; k < dof; ++k) { 6659 if ((cind < cdof) && (k == cdofs[cind])) { 6660 ++cind; 6661 continue; 6662 } 6663 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6664 } 6665 } else { 6666 for (k = 0; k < dof; ++k) { 6667 if ((cind < cdof) && (k == cdofs[cind])) { 6668 ++cind; 6669 continue; 6670 } 6671 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6672 } 6673 } 6674 } 6675 } 6676 PetscFunctionReturn(PETSC_SUCCESS); 6677 } 6678 6679 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[]) 6680 { 6681 PetscInt cdof; /* The number of constraints on this point */ 6682 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6683 PetscScalar *a; 6684 PetscInt off, cind = 0, k; 6685 6686 PetscFunctionBegin; 6687 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6688 PetscCall(PetscSectionGetOffset(section, point, &off)); 6689 a = &array[off]; 6690 if (cdof) { 6691 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6692 if (clperm) { 6693 if (perm) { 6694 for (k = 0; k < dof; ++k) { 6695 if ((cind < cdof) && (k == cdofs[cind])) { 6696 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6697 cind++; 6698 } 6699 } 6700 } else { 6701 for (k = 0; k < dof; ++k) { 6702 if ((cind < cdof) && (k == cdofs[cind])) { 6703 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6704 cind++; 6705 } 6706 } 6707 } 6708 } else { 6709 if (perm) { 6710 for (k = 0; k < dof; ++k) { 6711 if ((cind < cdof) && (k == cdofs[cind])) { 6712 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6713 cind++; 6714 } 6715 } 6716 } else { 6717 for (k = 0; k < dof; ++k) { 6718 if ((cind < cdof) && (k == cdofs[cind])) { 6719 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6720 cind++; 6721 } 6722 } 6723 } 6724 } 6725 } 6726 PetscFunctionReturn(PETSC_SUCCESS); 6727 } 6728 6729 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[]) 6730 { 6731 PetscScalar *a; 6732 PetscInt fdof, foff, fcdof, foffset = *offset; 6733 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6734 PetscInt cind = 0, b; 6735 6736 PetscFunctionBegin; 6737 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6738 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6739 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6740 a = &array[foff]; 6741 if (!fcdof || setBC) { 6742 if (clperm) { 6743 if (perm) { 6744 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6745 } else { 6746 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6747 } 6748 } else { 6749 if (perm) { 6750 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6751 } else { 6752 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6753 } 6754 } 6755 } else { 6756 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6757 if (clperm) { 6758 if (perm) { 6759 for (b = 0; b < fdof; b++) { 6760 if ((cind < fcdof) && (b == fcdofs[cind])) { 6761 ++cind; 6762 continue; 6763 } 6764 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6765 } 6766 } else { 6767 for (b = 0; b < fdof; b++) { 6768 if ((cind < fcdof) && (b == fcdofs[cind])) { 6769 ++cind; 6770 continue; 6771 } 6772 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6773 } 6774 } 6775 } else { 6776 if (perm) { 6777 for (b = 0; b < fdof; b++) { 6778 if ((cind < fcdof) && (b == fcdofs[cind])) { 6779 ++cind; 6780 continue; 6781 } 6782 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6783 } 6784 } else { 6785 for (b = 0; b < fdof; b++) { 6786 if ((cind < fcdof) && (b == fcdofs[cind])) { 6787 ++cind; 6788 continue; 6789 } 6790 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6791 } 6792 } 6793 } 6794 } 6795 *offset += fdof; 6796 PetscFunctionReturn(PETSC_SUCCESS); 6797 } 6798 6799 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[]) 6800 { 6801 PetscScalar *a; 6802 PetscInt fdof, foff, fcdof, foffset = *offset; 6803 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6804 PetscInt Nc, cind = 0, ncind = 0, b; 6805 PetscBool ncSet, fcSet; 6806 6807 PetscFunctionBegin; 6808 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6809 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6810 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6811 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6812 a = &array[foff]; 6813 if (fcdof) { 6814 /* We just override fcdof and fcdofs with Ncc and comps */ 6815 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6816 if (clperm) { 6817 if (perm) { 6818 if (comps) { 6819 for (b = 0; b < fdof; b++) { 6820 ncSet = fcSet = PETSC_FALSE; 6821 if (b % Nc == comps[ncind]) { 6822 ncind = (ncind + 1) % Ncc; 6823 ncSet = PETSC_TRUE; 6824 } 6825 if ((cind < fcdof) && (b == fcdofs[cind])) { 6826 ++cind; 6827 fcSet = PETSC_TRUE; 6828 } 6829 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6830 } 6831 } else { 6832 for (b = 0; b < fdof; b++) { 6833 if ((cind < fcdof) && (b == fcdofs[cind])) { 6834 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6835 ++cind; 6836 } 6837 } 6838 } 6839 } else { 6840 if (comps) { 6841 for (b = 0; b < fdof; b++) { 6842 ncSet = fcSet = PETSC_FALSE; 6843 if (b % Nc == comps[ncind]) { 6844 ncind = (ncind + 1) % Ncc; 6845 ncSet = PETSC_TRUE; 6846 } 6847 if ((cind < fcdof) && (b == fcdofs[cind])) { 6848 ++cind; 6849 fcSet = PETSC_TRUE; 6850 } 6851 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6852 } 6853 } else { 6854 for (b = 0; b < fdof; b++) { 6855 if ((cind < fcdof) && (b == fcdofs[cind])) { 6856 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6857 ++cind; 6858 } 6859 } 6860 } 6861 } 6862 } else { 6863 if (perm) { 6864 if (comps) { 6865 for (b = 0; b < fdof; b++) { 6866 ncSet = fcSet = PETSC_FALSE; 6867 if (b % Nc == comps[ncind]) { 6868 ncind = (ncind + 1) % Ncc; 6869 ncSet = PETSC_TRUE; 6870 } 6871 if ((cind < fcdof) && (b == fcdofs[cind])) { 6872 ++cind; 6873 fcSet = PETSC_TRUE; 6874 } 6875 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6876 } 6877 } else { 6878 for (b = 0; b < fdof; b++) { 6879 if ((cind < fcdof) && (b == fcdofs[cind])) { 6880 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6881 ++cind; 6882 } 6883 } 6884 } 6885 } else { 6886 if (comps) { 6887 for (b = 0; b < fdof; b++) { 6888 ncSet = fcSet = PETSC_FALSE; 6889 if (b % Nc == comps[ncind]) { 6890 ncind = (ncind + 1) % Ncc; 6891 ncSet = PETSC_TRUE; 6892 } 6893 if ((cind < fcdof) && (b == fcdofs[cind])) { 6894 ++cind; 6895 fcSet = PETSC_TRUE; 6896 } 6897 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6898 } 6899 } else { 6900 for (b = 0; b < fdof; b++) { 6901 if ((cind < fcdof) && (b == fcdofs[cind])) { 6902 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6903 ++cind; 6904 } 6905 } 6906 } 6907 } 6908 } 6909 } 6910 *offset += fdof; 6911 PetscFunctionReturn(PETSC_SUCCESS); 6912 } 6913 6914 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6915 { 6916 PetscScalar *array; 6917 const PetscInt *cone, *coneO; 6918 PetscInt pStart, pEnd, p, numPoints, off, dof; 6919 6920 PetscFunctionBeginHot; 6921 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6922 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6923 PetscCall(DMPlexGetCone(dm, point, &cone)); 6924 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6925 PetscCall(VecGetArray(v, &array)); 6926 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6927 const PetscInt cp = !p ? point : cone[p - 1]; 6928 const PetscInt o = !p ? 0 : coneO[p - 1]; 6929 6930 if ((cp < pStart) || (cp >= pEnd)) { 6931 dof = 0; 6932 continue; 6933 } 6934 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6935 /* ADD_VALUES */ 6936 { 6937 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6938 PetscScalar *a; 6939 PetscInt cdof, coff, cind = 0, k; 6940 6941 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6942 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6943 a = &array[coff]; 6944 if (!cdof) { 6945 if (o >= 0) { 6946 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6947 } else { 6948 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6949 } 6950 } else { 6951 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6952 if (o >= 0) { 6953 for (k = 0; k < dof; ++k) { 6954 if ((cind < cdof) && (k == cdofs[cind])) { 6955 ++cind; 6956 continue; 6957 } 6958 a[k] += values[off + k]; 6959 } 6960 } else { 6961 for (k = 0; k < dof; ++k) { 6962 if ((cind < cdof) && (k == cdofs[cind])) { 6963 ++cind; 6964 continue; 6965 } 6966 a[k] += values[off + dof - k - 1]; 6967 } 6968 } 6969 } 6970 } 6971 } 6972 PetscCall(VecRestoreArray(v, &array)); 6973 PetscFunctionReturn(PETSC_SUCCESS); 6974 } 6975 6976 /*@C 6977 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6978 6979 Not collective 6980 6981 Input Parameters: 6982 + dm - The `DM` 6983 . section - The section describing the layout in `v`, or `NULL` to use the default section 6984 . v - The local vector 6985 . point - The point in the `DM` 6986 . values - The array of values 6987 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6988 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6989 6990 Level: intermediate 6991 6992 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6993 @*/ 6994 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6995 { 6996 PetscSection clSection; 6997 IS clPoints; 6998 PetscScalar *array; 6999 PetscInt *points = NULL; 7000 const PetscInt *clp, *clperm = NULL; 7001 PetscInt depth, numFields, numPoints, p, clsize; 7002 7003 PetscFunctionBeginHot; 7004 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7005 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7006 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7007 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7008 PetscCall(DMPlexGetDepth(dm, &depth)); 7009 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7010 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7011 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7012 PetscFunctionReturn(PETSC_SUCCESS); 7013 } 7014 /* Get points */ 7015 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7016 for (clsize = 0, p = 0; p < numPoints; p++) { 7017 PetscInt dof; 7018 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7019 clsize += dof; 7020 } 7021 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7022 /* Get array */ 7023 PetscCall(VecGetArray(v, &array)); 7024 /* Get values */ 7025 if (numFields > 0) { 7026 PetscInt offset = 0, f; 7027 for (f = 0; f < numFields; ++f) { 7028 const PetscInt **perms = NULL; 7029 const PetscScalar **flips = NULL; 7030 7031 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7032 switch (mode) { 7033 case INSERT_VALUES: 7034 for (p = 0; p < numPoints; p++) { 7035 const PetscInt point = points[2 * p]; 7036 const PetscInt *perm = perms ? perms[p] : NULL; 7037 const PetscScalar *flip = flips ? flips[p] : NULL; 7038 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7039 } 7040 break; 7041 case INSERT_ALL_VALUES: 7042 for (p = 0; p < numPoints; p++) { 7043 const PetscInt point = points[2 * p]; 7044 const PetscInt *perm = perms ? perms[p] : NULL; 7045 const PetscScalar *flip = flips ? flips[p] : NULL; 7046 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7047 } 7048 break; 7049 case INSERT_BC_VALUES: 7050 for (p = 0; p < numPoints; p++) { 7051 const PetscInt point = points[2 * p]; 7052 const PetscInt *perm = perms ? perms[p] : NULL; 7053 const PetscScalar *flip = flips ? flips[p] : NULL; 7054 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7055 } 7056 break; 7057 case ADD_VALUES: 7058 for (p = 0; p < numPoints; p++) { 7059 const PetscInt point = points[2 * p]; 7060 const PetscInt *perm = perms ? perms[p] : NULL; 7061 const PetscScalar *flip = flips ? flips[p] : NULL; 7062 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7063 } 7064 break; 7065 case ADD_ALL_VALUES: 7066 for (p = 0; p < numPoints; p++) { 7067 const PetscInt point = points[2 * p]; 7068 const PetscInt *perm = perms ? perms[p] : NULL; 7069 const PetscScalar *flip = flips ? flips[p] : NULL; 7070 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7071 } 7072 break; 7073 case ADD_BC_VALUES: 7074 for (p = 0; p < numPoints; p++) { 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(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7079 } 7080 break; 7081 default: 7082 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7083 } 7084 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7085 } 7086 } else { 7087 PetscInt dof, off; 7088 const PetscInt **perms = NULL; 7089 const PetscScalar **flips = NULL; 7090 7091 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7092 switch (mode) { 7093 case INSERT_VALUES: 7094 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7095 const PetscInt point = points[2 * p]; 7096 const PetscInt *perm = perms ? perms[p] : NULL; 7097 const PetscScalar *flip = flips ? flips[p] : NULL; 7098 PetscCall(PetscSectionGetDof(section, point, &dof)); 7099 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7100 } 7101 break; 7102 case INSERT_ALL_VALUES: 7103 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7104 const PetscInt point = points[2 * p]; 7105 const PetscInt *perm = perms ? perms[p] : NULL; 7106 const PetscScalar *flip = flips ? flips[p] : NULL; 7107 PetscCall(PetscSectionGetDof(section, point, &dof)); 7108 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7109 } 7110 break; 7111 case INSERT_BC_VALUES: 7112 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7113 const PetscInt point = points[2 * p]; 7114 const PetscInt *perm = perms ? perms[p] : NULL; 7115 const PetscScalar *flip = flips ? flips[p] : NULL; 7116 PetscCall(PetscSectionGetDof(section, point, &dof)); 7117 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7118 } 7119 break; 7120 case ADD_VALUES: 7121 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7122 const PetscInt point = points[2 * p]; 7123 const PetscInt *perm = perms ? perms[p] : NULL; 7124 const PetscScalar *flip = flips ? flips[p] : NULL; 7125 PetscCall(PetscSectionGetDof(section, point, &dof)); 7126 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7127 } 7128 break; 7129 case ADD_ALL_VALUES: 7130 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7131 const PetscInt point = points[2 * p]; 7132 const PetscInt *perm = perms ? perms[p] : NULL; 7133 const PetscScalar *flip = flips ? flips[p] : NULL; 7134 PetscCall(PetscSectionGetDof(section, point, &dof)); 7135 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7136 } 7137 break; 7138 case ADD_BC_VALUES: 7139 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7140 const PetscInt point = points[2 * p]; 7141 const PetscInt *perm = perms ? perms[p] : NULL; 7142 const PetscScalar *flip = flips ? flips[p] : NULL; 7143 PetscCall(PetscSectionGetDof(section, point, &dof)); 7144 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7145 } 7146 break; 7147 default: 7148 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7149 } 7150 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7151 } 7152 /* Cleanup points */ 7153 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7154 /* Cleanup array */ 7155 PetscCall(VecRestoreArray(v, &array)); 7156 PetscFunctionReturn(PETSC_SUCCESS); 7157 } 7158 7159 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7160 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7161 { 7162 PetscFunctionBegin; 7163 *contains = PETSC_TRUE; 7164 if (label) { 7165 PetscInt fdof; 7166 7167 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7168 if (!*contains) { 7169 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7170 *offset += fdof; 7171 PetscFunctionReturn(PETSC_SUCCESS); 7172 } 7173 } 7174 PetscFunctionReturn(PETSC_SUCCESS); 7175 } 7176 7177 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7178 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) 7179 { 7180 PetscSection clSection; 7181 IS clPoints; 7182 PetscScalar *array; 7183 PetscInt *points = NULL; 7184 const PetscInt *clp; 7185 PetscInt numFields, numPoints, p; 7186 PetscInt offset = 0, f; 7187 7188 PetscFunctionBeginHot; 7189 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7190 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7191 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7192 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7193 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7194 /* Get points */ 7195 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7196 /* Get array */ 7197 PetscCall(VecGetArray(v, &array)); 7198 /* Get values */ 7199 for (f = 0; f < numFields; ++f) { 7200 const PetscInt **perms = NULL; 7201 const PetscScalar **flips = NULL; 7202 PetscBool contains; 7203 7204 if (!fieldActive[f]) { 7205 for (p = 0; p < numPoints * 2; p += 2) { 7206 PetscInt fdof; 7207 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7208 offset += fdof; 7209 } 7210 continue; 7211 } 7212 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7213 switch (mode) { 7214 case INSERT_VALUES: 7215 for (p = 0; p < numPoints; p++) { 7216 const PetscInt point = points[2 * p]; 7217 const PetscInt *perm = perms ? perms[p] : NULL; 7218 const PetscScalar *flip = flips ? flips[p] : NULL; 7219 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7220 if (!contains) continue; 7221 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7222 } 7223 break; 7224 case INSERT_ALL_VALUES: 7225 for (p = 0; p < numPoints; p++) { 7226 const PetscInt point = points[2 * p]; 7227 const PetscInt *perm = perms ? perms[p] : NULL; 7228 const PetscScalar *flip = flips ? flips[p] : NULL; 7229 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7230 if (!contains) continue; 7231 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7232 } 7233 break; 7234 case INSERT_BC_VALUES: 7235 for (p = 0; p < numPoints; p++) { 7236 const PetscInt point = points[2 * p]; 7237 const PetscInt *perm = perms ? perms[p] : NULL; 7238 const PetscScalar *flip = flips ? flips[p] : NULL; 7239 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7240 if (!contains) continue; 7241 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7242 } 7243 break; 7244 case ADD_VALUES: 7245 for (p = 0; p < numPoints; p++) { 7246 const PetscInt point = points[2 * p]; 7247 const PetscInt *perm = perms ? perms[p] : NULL; 7248 const PetscScalar *flip = flips ? flips[p] : NULL; 7249 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7250 if (!contains) continue; 7251 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7252 } 7253 break; 7254 case ADD_ALL_VALUES: 7255 for (p = 0; p < numPoints; p++) { 7256 const PetscInt point = points[2 * p]; 7257 const PetscInt *perm = perms ? perms[p] : NULL; 7258 const PetscScalar *flip = flips ? flips[p] : NULL; 7259 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7260 if (!contains) continue; 7261 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7262 } 7263 break; 7264 default: 7265 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7266 } 7267 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7268 } 7269 /* Cleanup points */ 7270 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7271 /* Cleanup array */ 7272 PetscCall(VecRestoreArray(v, &array)); 7273 PetscFunctionReturn(PETSC_SUCCESS); 7274 } 7275 7276 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7277 { 7278 PetscMPIInt rank; 7279 PetscInt i, j; 7280 7281 PetscFunctionBegin; 7282 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7283 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7284 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7285 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7286 numCIndices = numCIndices ? numCIndices : numRIndices; 7287 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7288 for (i = 0; i < numRIndices; i++) { 7289 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7290 for (j = 0; j < numCIndices; j++) { 7291 #if defined(PETSC_USE_COMPLEX) 7292 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7293 #else 7294 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7295 #endif 7296 } 7297 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7298 } 7299 PetscFunctionReturn(PETSC_SUCCESS); 7300 } 7301 7302 /* 7303 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7304 7305 Input Parameters: 7306 + section - The section for this data layout 7307 . islocal - Is the section (and thus indices being requested) local or global? 7308 . point - The point contributing dofs with these indices 7309 . off - The global offset of this point 7310 . loff - The local offset of each field 7311 . setBC - The flag determining whether to include indices of boundary values 7312 . perm - A permutation of the dofs on this point, or NULL 7313 - indperm - A permutation of the entire indices array, or NULL 7314 7315 Output Parameter: 7316 . indices - Indices for dofs on this point 7317 7318 Level: developer 7319 7320 Note: The indices could be local or global, depending on the value of 'off'. 7321 */ 7322 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7323 { 7324 PetscInt dof; /* The number of unknowns on this point */ 7325 PetscInt cdof; /* The number of constraints on this point */ 7326 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7327 PetscInt cind = 0, k; 7328 7329 PetscFunctionBegin; 7330 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7331 PetscCall(PetscSectionGetDof(section, point, &dof)); 7332 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7333 if (!cdof || setBC) { 7334 for (k = 0; k < dof; ++k) { 7335 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7336 const PetscInt ind = indperm ? indperm[preind] : preind; 7337 7338 indices[ind] = off + k; 7339 } 7340 } else { 7341 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7342 for (k = 0; k < dof; ++k) { 7343 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7344 const PetscInt ind = indperm ? indperm[preind] : preind; 7345 7346 if ((cind < cdof) && (k == cdofs[cind])) { 7347 /* Insert check for returning constrained indices */ 7348 indices[ind] = -(off + k + 1); 7349 ++cind; 7350 } else { 7351 indices[ind] = off + k - (islocal ? 0 : cind); 7352 } 7353 } 7354 } 7355 *loff += dof; 7356 PetscFunctionReturn(PETSC_SUCCESS); 7357 } 7358 7359 /* 7360 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7361 7362 Input Parameters: 7363 + section - a section (global or local) 7364 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7365 . point - point within section 7366 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7367 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7368 . setBC - identify constrained (boundary condition) points via involution. 7369 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7370 . permsoff - offset 7371 - indperm - index permutation 7372 7373 Output Parameter: 7374 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7375 . indices - array to hold indices (as defined by section) of each dof associated with point 7376 7377 Notes: 7378 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7379 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7380 in the local vector. 7381 7382 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7383 significant). It is invalid to call with a global section and setBC=true. 7384 7385 Developer Note: 7386 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7387 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7388 offset could be obtained from the section instead of passing it explicitly as we do now. 7389 7390 Example: 7391 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7392 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7393 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7394 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. 7395 7396 Level: developer 7397 */ 7398 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[]) 7399 { 7400 PetscInt numFields, foff, f; 7401 7402 PetscFunctionBegin; 7403 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7404 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7405 for (f = 0, foff = 0; f < numFields; ++f) { 7406 PetscInt fdof, cfdof; 7407 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7408 PetscInt cind = 0, b; 7409 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7410 7411 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7412 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7413 if (!cfdof || setBC) { 7414 for (b = 0; b < fdof; ++b) { 7415 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7416 const PetscInt ind = indperm ? indperm[preind] : preind; 7417 7418 indices[ind] = off + foff + b; 7419 } 7420 } else { 7421 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7422 for (b = 0; b < fdof; ++b) { 7423 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7424 const PetscInt ind = indperm ? indperm[preind] : preind; 7425 7426 if ((cind < cfdof) && (b == fcdofs[cind])) { 7427 indices[ind] = -(off + foff + b + 1); 7428 ++cind; 7429 } else { 7430 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7431 } 7432 } 7433 } 7434 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7435 foffs[f] += fdof; 7436 } 7437 PetscFunctionReturn(PETSC_SUCCESS); 7438 } 7439 7440 /* 7441 This version believes the globalSection offsets for each field, rather than just the point offset 7442 7443 . foffs - The offset into 'indices' for each field, since it is segregated by field 7444 7445 Notes: 7446 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7447 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7448 */ 7449 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7450 { 7451 PetscInt numFields, foff, f; 7452 7453 PetscFunctionBegin; 7454 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7455 for (f = 0; f < numFields; ++f) { 7456 PetscInt fdof, cfdof; 7457 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7458 PetscInt cind = 0, b; 7459 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7460 7461 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7462 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7463 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7464 if (!cfdof) { 7465 for (b = 0; b < fdof; ++b) { 7466 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7467 const PetscInt ind = indperm ? indperm[preind] : preind; 7468 7469 indices[ind] = foff + b; 7470 } 7471 } else { 7472 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7473 for (b = 0; b < fdof; ++b) { 7474 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7475 const PetscInt ind = indperm ? indperm[preind] : preind; 7476 7477 if ((cind < cfdof) && (b == fcdofs[cind])) { 7478 indices[ind] = -(foff + b + 1); 7479 ++cind; 7480 } else { 7481 indices[ind] = foff + b - cind; 7482 } 7483 } 7484 } 7485 foffs[f] += fdof; 7486 } 7487 PetscFunctionReturn(PETSC_SUCCESS); 7488 } 7489 7490 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7491 { 7492 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7493 7494 PetscFunctionBegin; 7495 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7496 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7497 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7498 for (PetscInt p = 0; p < nPoints; p++) { 7499 PetscInt b = pnts[2 * p]; 7500 PetscInt bSecDof = 0, bOff; 7501 PetscInt cSecDof = 0; 7502 PetscSection indices_section; 7503 7504 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7505 if (!bSecDof) continue; 7506 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7507 indices_section = cSecDof > 0 ? cSec : section; 7508 if (numFields) { 7509 PetscInt fStart[32], fEnd[32]; 7510 7511 fStart[0] = 0; 7512 fEnd[0] = 0; 7513 for (PetscInt f = 0; f < numFields; f++) { 7514 PetscInt fDof = 0; 7515 7516 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7517 fStart[f + 1] = fStart[f] + fDof; 7518 fEnd[f + 1] = fStart[f + 1]; 7519 } 7520 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7521 // only apply permutations on one side 7522 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7523 for (PetscInt f = 0; f < numFields; f++) { 7524 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7525 } 7526 } else { 7527 PetscInt bEnd = 0; 7528 7529 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7530 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7531 7532 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7533 } 7534 } 7535 PetscFunctionReturn(PETSC_SUCCESS); 7536 } 7537 7538 PETSC_INTERN PetscErrorCode DMPlexAnchorsGetSubMatModification(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscInt offsets[], PetscScalar *outMat[]) 7539 { 7540 Mat cMat; 7541 PetscSection aSec, cSec; 7542 IS aIS; 7543 PetscInt aStart = -1, aEnd = -1; 7544 PetscInt sStart = -1, sEnd = -1; 7545 PetscInt cStart = -1, cEnd = -1; 7546 const PetscInt *anchors; 7547 PetscInt numFields, p; 7548 PetscInt newNumPoints = 0, newNumIndices = 0; 7549 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7550 PetscInt oldOffsets[32]; 7551 PetscInt newOffsets[32]; 7552 PetscInt oldOffsetsCopy[32]; 7553 PetscInt newOffsetsCopy[32]; 7554 PetscScalar *modMat = NULL; 7555 PetscBool anyConstrained = PETSC_FALSE; 7556 7557 PetscFunctionBegin; 7558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7559 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7560 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7561 7562 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7563 /* if there are point-to-point constraints */ 7564 if (aSec) { 7565 PetscCall(PetscArrayzero(newOffsets, 32)); 7566 PetscCall(PetscArrayzero(oldOffsets, 32)); 7567 PetscCall(ISGetIndices(aIS, &anchors)); 7568 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7569 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7570 /* figure out how many points are going to be in the new element matrix 7571 * (we allow double counting, because it's all just going to be summed 7572 * into the global matrix anyway) */ 7573 for (p = 0; p < 2 * numPoints; p += 2) { 7574 PetscInt b = points[p]; 7575 PetscInt bDof = 0, bSecDof = 0; 7576 7577 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7578 if (!bSecDof) continue; 7579 7580 for (PetscInt f = 0; f < numFields; f++) { 7581 PetscInt fDof = 0; 7582 7583 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7584 oldOffsets[f + 1] += fDof; 7585 } 7586 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7587 if (bDof) { 7588 /* this point is constrained */ 7589 /* it is going to be replaced by its anchors */ 7590 PetscInt bOff, q; 7591 7592 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7593 for (q = 0; q < bDof; q++) { 7594 PetscInt a = anchors[bOff + q]; 7595 PetscInt aDof = 0; 7596 7597 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7598 if (aDof) { 7599 anyConstrained = PETSC_TRUE; 7600 newNumPoints += 1; 7601 } 7602 newNumIndices += aDof; 7603 for (PetscInt f = 0; f < numFields; ++f) { 7604 PetscInt fDof = 0; 7605 7606 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7607 newOffsets[f + 1] += fDof; 7608 } 7609 } 7610 } else { 7611 /* this point is not constrained */ 7612 newNumPoints++; 7613 newNumIndices += bSecDof; 7614 for (PetscInt f = 0; f < numFields; ++f) { 7615 PetscInt fDof; 7616 7617 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7618 newOffsets[f + 1] += fDof; 7619 } 7620 } 7621 } 7622 } 7623 if (!anyConstrained) { 7624 if (outNumPoints) *outNumPoints = 0; 7625 if (outNumIndices) *outNumIndices = 0; 7626 if (outPoints) *outPoints = NULL; 7627 if (outMat) *outMat = NULL; 7628 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7629 PetscFunctionReturn(PETSC_SUCCESS); 7630 } 7631 7632 if (outNumPoints) *outNumPoints = newNumPoints; 7633 if (outNumIndices) *outNumIndices = newNumIndices; 7634 7635 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7636 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7637 7638 if (!outPoints && !outMat) { 7639 if (offsets) { 7640 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7641 } 7642 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7643 PetscFunctionReturn(PETSC_SUCCESS); 7644 } 7645 7646 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7647 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7648 7649 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7650 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7651 7652 /* output arrays */ 7653 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7654 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7655 7656 // get the new Points 7657 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7658 PetscInt b = points[2 * p]; 7659 PetscInt bDof = 0, bSecDof = 0, bOff; 7660 7661 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7662 if (!bSecDof) continue; 7663 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7664 if (bDof) { 7665 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7666 for (PetscInt q = 0; q < bDof; q++) { 7667 PetscInt a = anchors[bOff + q], aDof = 0; 7668 7669 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7670 if (aDof) { 7671 newPoints[2 * newP] = a; 7672 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7673 newP++; 7674 } 7675 } 7676 } else { 7677 newPoints[2 * newP] = b; 7678 newPoints[2 * newP + 1] = points[2 * p + 1]; 7679 newP++; 7680 } 7681 } 7682 7683 if (outMat) { 7684 PetscScalar *tmpMat; 7685 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7686 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7687 7688 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7689 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7690 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7691 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7692 7693 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7694 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7695 7696 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7697 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7698 7699 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7700 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7701 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7702 // for each field, insert the anchor modification into modMat 7703 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7704 PetscInt fStart = oldOffsets[f]; 7705 PetscInt fNewStart = newOffsets[f]; 7706 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7707 PetscInt b = points[2 * p]; 7708 PetscInt bDof = 0, bSecDof = 0, bOff; 7709 7710 if (b >= sStart && b < sEnd) { 7711 if (numFields) { 7712 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7713 } else { 7714 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7715 } 7716 } 7717 if (!bSecDof) continue; 7718 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7719 if (bDof) { 7720 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7721 for (PetscInt q = 0; q < bDof; q++, newP++) { 7722 PetscInt a = anchors[bOff + q], aDof = 0; 7723 7724 if (a >= sStart && a < sEnd) { 7725 if (numFields) { 7726 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7727 } else { 7728 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7729 } 7730 } 7731 if (aDof) { 7732 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7733 for (PetscInt d = 0; d < bSecDof; d++) { 7734 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7735 } 7736 } 7737 oNew += aDof; 7738 } 7739 } else { 7740 // Insert the identity matrix in this block 7741 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7742 oNew += bSecDof; 7743 newP++; 7744 } 7745 o += bSecDof; 7746 } 7747 } 7748 7749 *outMat = modMat; 7750 7751 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7752 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7753 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7754 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7755 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7756 } 7757 PetscCall(ISRestoreIndices(aIS, &anchors)); 7758 7759 /* output */ 7760 if (outPoints) { 7761 *outPoints = newPoints; 7762 } else { 7763 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7764 } 7765 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7766 PetscFunctionReturn(PETSC_SUCCESS); 7767 } 7768 7769 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat_Internal(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt numRows, PetscInt numCols, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyRight, PetscBool multiplyLeft) 7770 { 7771 PetscScalar *modMat = NULL; 7772 PetscInt newNumIndices = -1; 7773 7774 PetscFunctionBegin; 7775 /* If M is the matrix represented by values, get the matrix C such that we will add M * C (or, if multiplyLeft, C^T * M * C) into the global matrix. 7776 modMat is that matrix C */ 7777 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7778 if (outNumIndices) *outNumIndices = newNumIndices; 7779 if (modMat) { 7780 const PetscScalar *newValues = values; 7781 7782 if (multiplyRight) { 7783 PetscScalar *newNewValues = NULL; 7784 PetscBLASInt M = newNumIndices; 7785 PetscBLASInt N = numRows; 7786 PetscBLASInt K = numIndices; 7787 PetscScalar a = 1.0, b = 0.0; 7788 7789 PetscCheck(numCols == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of columns: %" PetscInt_FMT ", expected %" PetscInt_FMT, numCols, numIndices); 7790 7791 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7792 // row-major to column-major conversion, right multiplication becomes left multiplication 7793 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7794 7795 numCols = newNumIndices; 7796 newValues = newNewValues; 7797 } 7798 7799 if (multiplyLeft) { 7800 PetscScalar *newNewValues = NULL; 7801 PetscBLASInt M = numCols; 7802 PetscBLASInt N = newNumIndices; 7803 PetscBLASInt K = numIndices; 7804 PetscScalar a = 1.0, b = 0.0; 7805 7806 PetscCheck(numRows == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of rows: %" PetscInt_FMT ", expected %" PetscInt_FMT, numRows, numIndices); 7807 7808 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7809 // row-major to column-major conversion, left multiplication becomes right multiplication 7810 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7811 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7812 newValues = newNewValues; 7813 } 7814 *outValues = (PetscScalar *)newValues; 7815 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7816 } 7817 PetscFunctionReturn(PETSC_SUCCESS); 7818 } 7819 7820 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft) 7821 { 7822 PetscFunctionBegin; 7823 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7824 PetscFunctionReturn(PETSC_SUCCESS); 7825 } 7826 7827 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7828 { 7829 /* Closure ordering */ 7830 PetscSection clSection; 7831 IS clPoints; 7832 const PetscInt *clp; 7833 PetscInt *points; 7834 PetscInt Ncl, Ni = 0; 7835 7836 PetscFunctionBeginHot; 7837 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7838 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7839 PetscInt dof; 7840 7841 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7842 Ni += dof; 7843 } 7844 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7845 *closureSize = Ni; 7846 PetscFunctionReturn(PETSC_SUCCESS); 7847 } 7848 7849 static PetscErrorCode DMPlexGetClosureIndices_Internal(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numRows, PetscInt *numCols, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[], PetscBool multiplyRight, PetscBool multiplyLeft) 7850 { 7851 /* Closure ordering */ 7852 PetscSection clSection; 7853 IS clPoints; 7854 const PetscInt *clp; 7855 PetscInt *points; 7856 const PetscInt *clperm = NULL; 7857 /* Dof permutation and sign flips */ 7858 const PetscInt **perms[32] = {NULL}; 7859 const PetscScalar **flips[32] = {NULL}; 7860 PetscScalar *valCopy = NULL; 7861 /* Hanging node constraints */ 7862 PetscInt *pointsC = NULL; 7863 PetscScalar *valuesC = NULL; 7864 PetscInt NclC, NiC; 7865 7866 PetscInt *idx; 7867 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7868 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7869 PetscInt idxStart, idxEnd; 7870 PetscInt nRows, nCols; 7871 7872 PetscFunctionBeginHot; 7873 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7874 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7875 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7876 PetscAssertPointer(numRows, 6); 7877 PetscAssertPointer(numCols, 7); 7878 if (indices) PetscAssertPointer(indices, 8); 7879 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7880 if (values) PetscAssertPointer(values, 10); 7881 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7882 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7883 PetscCall(PetscArrayzero(offsets, 32)); 7884 /* 1) Get points in closure */ 7885 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7886 if (useClPerm) { 7887 PetscInt depth, clsize; 7888 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7889 for (clsize = 0, p = 0; p < Ncl; p++) { 7890 PetscInt dof; 7891 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7892 clsize += dof; 7893 } 7894 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7895 } 7896 /* 2) Get number of indices on these points and field offsets from section */ 7897 for (p = 0; p < Ncl * 2; p += 2) { 7898 PetscInt dof, fdof; 7899 7900 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7901 for (f = 0; f < Nf; ++f) { 7902 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7903 offsets[f + 1] += fdof; 7904 } 7905 Ni += dof; 7906 } 7907 if (*numRows == -1) *numRows = Ni; 7908 if (*numCols == -1) *numCols = Ni; 7909 nRows = *numRows; 7910 nCols = *numCols; 7911 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7912 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7913 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7914 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7915 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7916 for (f = 0; f < PetscMax(1, Nf); ++f) { 7917 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7918 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7919 /* may need to apply sign changes to the element matrix */ 7920 if (values && flips[f]) { 7921 PetscInt foffset = offsets[f]; 7922 7923 for (p = 0; p < Ncl; ++p) { 7924 PetscInt pnt = points[2 * p], fdof; 7925 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7926 7927 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7928 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7929 if (flip) { 7930 PetscInt i, j, k; 7931 7932 if (!valCopy) { 7933 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7934 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7935 *values = valCopy; 7936 } 7937 for (i = 0; i < fdof; ++i) { 7938 PetscScalar fval = flip[i]; 7939 7940 if (multiplyRight) { 7941 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 7942 } 7943 if (multiplyLeft) { 7944 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 7945 } 7946 } 7947 } 7948 foffset += fdof; 7949 } 7950 } 7951 } 7952 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7953 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 7954 if (NclC) { 7955 if (multiplyRight) { *numCols = nCols = NiC; } 7956 if (multiplyLeft) { *numRows = nRows = NiC; } 7957 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7958 for (f = 0; f < PetscMax(1, Nf); ++f) { 7959 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7960 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7961 } 7962 for (f = 0; f < PetscMax(1, Nf); ++f) { 7963 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7964 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7965 } 7966 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7967 Ncl = NclC; 7968 Ni = NiC; 7969 points = pointsC; 7970 if (values) *values = valuesC; 7971 } 7972 /* 5) Calculate indices */ 7973 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7974 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 7975 if (Nf) { 7976 PetscInt idxOff; 7977 PetscBool useFieldOffsets; 7978 7979 if (outOffsets) { 7980 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7981 } 7982 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7983 if (useFieldOffsets) { 7984 for (p = 0; p < Ncl; ++p) { 7985 const PetscInt pnt = points[p * 2]; 7986 7987 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7988 } 7989 } else { 7990 for (p = 0; p < Ncl; ++p) { 7991 const PetscInt pnt = points[p * 2]; 7992 7993 if (pnt < idxStart || pnt >= idxEnd) continue; 7994 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7995 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7996 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7997 * global section. */ 7998 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7999 } 8000 } 8001 } else { 8002 PetscInt off = 0, idxOff; 8003 8004 for (p = 0; p < Ncl; ++p) { 8005 const PetscInt pnt = points[p * 2]; 8006 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8007 8008 if (pnt < idxStart || pnt >= idxEnd) continue; 8009 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8010 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8011 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8012 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8013 } 8014 } 8015 /* 6) Cleanup */ 8016 for (f = 0; f < PetscMax(1, Nf); ++f) { 8017 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8018 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8019 } 8020 if (NclC) { 8021 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8022 } else { 8023 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8024 } 8025 8026 if (indices) *indices = idx; 8027 PetscFunctionReturn(PETSC_SUCCESS); 8028 } 8029 8030 /*@C 8031 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8032 8033 Not collective 8034 8035 Input Parameters: 8036 + dm - The `DM` 8037 . section - The `PetscSection` describing the points (a local section) 8038 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8039 . point - The point defining the closure 8040 - useClPerm - Use the closure point permutation if available 8041 8042 Output Parameters: 8043 + numIndices - The number of dof indices in the closure of point with the input sections 8044 . indices - The dof indices 8045 . outOffsets - Array to write the field offsets into, or `NULL` 8046 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8047 8048 Level: advanced 8049 8050 Notes: 8051 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 8052 8053 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8054 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8055 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8056 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8057 indices (with the above semantics) are implied. 8058 8059 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8060 `PetscSection`, `DMGetGlobalSection()` 8061 @*/ 8062 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8063 { 8064 PetscInt numRows = -1, numCols = -1; 8065 8066 PetscFunctionBeginHot; 8067 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8068 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8069 *numIndices = numRows; 8070 PetscFunctionReturn(PETSC_SUCCESS); 8071 } 8072 8073 /*@C 8074 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8075 8076 Not collective 8077 8078 Input Parameters: 8079 + dm - The `DM` 8080 . section - The `PetscSection` describing the points (a local section) 8081 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8082 . point - The point defining the closure 8083 - useClPerm - Use the closure point permutation if available 8084 8085 Output Parameters: 8086 + numIndices - The number of dof indices in the closure of point with the input sections 8087 . indices - The dof indices 8088 . outOffsets - Array to write the field offsets into, or `NULL` 8089 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8090 8091 Level: advanced 8092 8093 Notes: 8094 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8095 8096 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8097 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8098 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8099 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8100 indices (with the above semantics) are implied. 8101 8102 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8103 @*/ 8104 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8105 { 8106 PetscFunctionBegin; 8107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8108 PetscAssertPointer(indices, 7); 8109 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8110 PetscFunctionReturn(PETSC_SUCCESS); 8111 } 8112 8113 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8114 { 8115 DM_Plex *mesh = (DM_Plex *)dm->data; 8116 PetscInt *indices; 8117 PetscInt numIndices; 8118 const PetscScalar *valuesOrig = values; 8119 PetscErrorCode ierr; 8120 8121 PetscFunctionBegin; 8122 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8123 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8124 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8125 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8126 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8127 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8128 8129 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8130 8131 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8132 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8133 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8134 if (ierr) { 8135 PetscMPIInt rank; 8136 8137 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8138 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8139 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8140 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8141 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8142 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8143 } 8144 if (mesh->printFEM > 1) { 8145 PetscInt i; 8146 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8147 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8148 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8149 } 8150 8151 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8152 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8153 PetscFunctionReturn(PETSC_SUCCESS); 8154 } 8155 8156 /*@C 8157 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8158 8159 Not collective 8160 8161 Input Parameters: 8162 + dm - The `DM` 8163 . section - The section describing the layout in `v`, or `NULL` to use the default section 8164 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8165 . A - The matrix 8166 . point - The point in the `DM` 8167 . values - The array of values 8168 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8169 8170 Level: intermediate 8171 8172 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8173 @*/ 8174 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8175 { 8176 PetscFunctionBegin; 8177 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8178 PetscFunctionReturn(PETSC_SUCCESS); 8179 } 8180 8181 /*@C 8182 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8183 8184 Not collective 8185 8186 Input Parameters: 8187 + dmRow - The `DM` for the row fields 8188 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8189 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8190 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8191 . dmCol - The `DM` for the column fields 8192 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8193 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8194 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8195 . A - The matrix 8196 . point - The point in the `DM` 8197 . values - The array of values 8198 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8199 8200 Level: intermediate 8201 8202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8203 @*/ 8204 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) 8205 { 8206 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8207 PetscInt *indicesRow, *indicesCol; 8208 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8209 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8210 8211 PetscErrorCode ierr; 8212 8213 PetscFunctionBegin; 8214 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8215 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8216 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8217 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8218 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8219 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8220 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8221 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8222 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8223 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8224 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8225 8226 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8227 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8228 valuesV1 = valuesV0; 8229 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8230 valuesV2 = valuesV1; 8231 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8232 8233 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8234 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8235 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8236 if (ierr) { 8237 PetscMPIInt rank; 8238 8239 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8240 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8241 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8242 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8243 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8244 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8245 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8246 } 8247 8248 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8249 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8250 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8251 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8252 PetscFunctionReturn(PETSC_SUCCESS); 8253 } 8254 8255 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8256 { 8257 DM_Plex *mesh = (DM_Plex *)dmf->data; 8258 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8259 PetscInt *cpoints = NULL; 8260 PetscInt *findices, *cindices; 8261 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8262 PetscInt foffsets[32], coffsets[32]; 8263 DMPolytopeType ct; 8264 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8265 PetscErrorCode ierr; 8266 8267 PetscFunctionBegin; 8268 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8269 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8270 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8271 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8272 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8273 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8274 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8275 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8276 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8277 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8278 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8279 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8280 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8281 PetscCall(PetscArrayzero(foffsets, 32)); 8282 PetscCall(PetscArrayzero(coffsets, 32)); 8283 /* Column indices */ 8284 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8285 maxFPoints = numCPoints; 8286 /* Compress out points not in the section */ 8287 /* TODO: Squeeze out points with 0 dof as well */ 8288 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8289 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8290 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8291 cpoints[q * 2] = cpoints[p]; 8292 cpoints[q * 2 + 1] = cpoints[p + 1]; 8293 ++q; 8294 } 8295 } 8296 numCPoints = q; 8297 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8298 PetscInt fdof; 8299 8300 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8301 if (!dof) continue; 8302 for (f = 0; f < numFields; ++f) { 8303 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8304 coffsets[f + 1] += fdof; 8305 } 8306 numCIndices += dof; 8307 } 8308 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8309 /* Row indices */ 8310 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8311 { 8312 DMPlexTransform tr; 8313 DMPolytopeType *rct; 8314 PetscInt *rsize, *rcone, *rornt, Nt; 8315 8316 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8317 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8318 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8319 numSubcells = rsize[Nt - 1]; 8320 PetscCall(DMPlexTransformDestroy(&tr)); 8321 } 8322 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8323 for (r = 0, q = 0; r < numSubcells; ++r) { 8324 /* TODO Map from coarse to fine cells */ 8325 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8326 /* Compress out points not in the section */ 8327 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8328 for (p = 0; p < numFPoints * 2; p += 2) { 8329 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8330 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8331 if (!dof) continue; 8332 for (s = 0; s < q; ++s) 8333 if (fpoints[p] == ftotpoints[s * 2]) break; 8334 if (s < q) continue; 8335 ftotpoints[q * 2] = fpoints[p]; 8336 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8337 ++q; 8338 } 8339 } 8340 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8341 } 8342 numFPoints = q; 8343 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8344 PetscInt fdof; 8345 8346 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8347 if (!dof) continue; 8348 for (f = 0; f < numFields; ++f) { 8349 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8350 foffsets[f + 1] += fdof; 8351 } 8352 numFIndices += dof; 8353 } 8354 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8355 8356 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8357 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8358 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8359 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8360 if (numFields) { 8361 const PetscInt **permsF[32] = {NULL}; 8362 const PetscInt **permsC[32] = {NULL}; 8363 8364 for (f = 0; f < numFields; f++) { 8365 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8366 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8367 } 8368 for (p = 0; p < numFPoints; p++) { 8369 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8370 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8371 } 8372 for (p = 0; p < numCPoints; p++) { 8373 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8374 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8375 } 8376 for (f = 0; f < numFields; f++) { 8377 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8378 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8379 } 8380 } else { 8381 const PetscInt **permsF = NULL; 8382 const PetscInt **permsC = NULL; 8383 8384 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8385 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8386 for (p = 0, off = 0; p < numFPoints; p++) { 8387 const PetscInt *perm = permsF ? permsF[p] : NULL; 8388 8389 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8390 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8391 } 8392 for (p = 0, off = 0; p < numCPoints; p++) { 8393 const PetscInt *perm = permsC ? permsC[p] : NULL; 8394 8395 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8396 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8397 } 8398 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8399 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8400 } 8401 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8402 /* TODO: flips */ 8403 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8404 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8405 if (ierr) { 8406 PetscMPIInt rank; 8407 8408 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8409 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8410 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8411 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8412 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8413 } 8414 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8415 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8416 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8417 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8418 PetscFunctionReturn(PETSC_SUCCESS); 8419 } 8420 8421 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8422 { 8423 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8424 PetscInt *cpoints = NULL; 8425 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8426 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8427 DMPolytopeType ct; 8428 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8429 8430 PetscFunctionBegin; 8431 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8432 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8433 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8434 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8435 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8436 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8437 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8438 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8439 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8440 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8441 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8442 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8443 /* Column indices */ 8444 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8445 maxFPoints = numCPoints; 8446 /* Compress out points not in the section */ 8447 /* TODO: Squeeze out points with 0 dof as well */ 8448 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8449 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8450 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8451 cpoints[q * 2] = cpoints[p]; 8452 cpoints[q * 2 + 1] = cpoints[p + 1]; 8453 ++q; 8454 } 8455 } 8456 numCPoints = q; 8457 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8458 PetscInt fdof; 8459 8460 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8461 if (!dof) continue; 8462 for (f = 0; f < numFields; ++f) { 8463 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8464 coffsets[f + 1] += fdof; 8465 } 8466 numCIndices += dof; 8467 } 8468 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8469 /* Row indices */ 8470 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8471 { 8472 DMPlexTransform tr; 8473 DMPolytopeType *rct; 8474 PetscInt *rsize, *rcone, *rornt, Nt; 8475 8476 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8477 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8478 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8479 numSubcells = rsize[Nt - 1]; 8480 PetscCall(DMPlexTransformDestroy(&tr)); 8481 } 8482 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8483 for (r = 0, q = 0; r < numSubcells; ++r) { 8484 /* TODO Map from coarse to fine cells */ 8485 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8486 /* Compress out points not in the section */ 8487 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8488 for (p = 0; p < numFPoints * 2; p += 2) { 8489 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8490 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8491 if (!dof) continue; 8492 for (s = 0; s < q; ++s) 8493 if (fpoints[p] == ftotpoints[s * 2]) break; 8494 if (s < q) continue; 8495 ftotpoints[q * 2] = fpoints[p]; 8496 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8497 ++q; 8498 } 8499 } 8500 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8501 } 8502 numFPoints = q; 8503 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8504 PetscInt fdof; 8505 8506 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8507 if (!dof) continue; 8508 for (f = 0; f < numFields; ++f) { 8509 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8510 foffsets[f + 1] += fdof; 8511 } 8512 numFIndices += dof; 8513 } 8514 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8515 8516 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8517 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8518 if (numFields) { 8519 const PetscInt **permsF[32] = {NULL}; 8520 const PetscInt **permsC[32] = {NULL}; 8521 8522 for (f = 0; f < numFields; f++) { 8523 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8524 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8525 } 8526 for (p = 0; p < numFPoints; p++) { 8527 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8528 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8529 } 8530 for (p = 0; p < numCPoints; p++) { 8531 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8532 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8533 } 8534 for (f = 0; f < numFields; f++) { 8535 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8536 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8537 } 8538 } else { 8539 const PetscInt **permsF = NULL; 8540 const PetscInt **permsC = NULL; 8541 8542 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8543 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8544 for (p = 0, off = 0; p < numFPoints; p++) { 8545 const PetscInt *perm = permsF ? permsF[p] : NULL; 8546 8547 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8548 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8549 } 8550 for (p = 0, off = 0; p < numCPoints; p++) { 8551 const PetscInt *perm = permsC ? permsC[p] : NULL; 8552 8553 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8554 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8555 } 8556 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8557 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8558 } 8559 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8560 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8561 PetscFunctionReturn(PETSC_SUCCESS); 8562 } 8563 8564 /*@ 8565 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8566 8567 Input Parameter: 8568 . dm - The `DMPLEX` object 8569 8570 Output Parameter: 8571 . cellHeight - The height of a cell 8572 8573 Level: developer 8574 8575 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8576 @*/ 8577 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8578 { 8579 DM_Plex *mesh = (DM_Plex *)dm->data; 8580 8581 PetscFunctionBegin; 8582 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8583 PetscAssertPointer(cellHeight, 2); 8584 *cellHeight = mesh->vtkCellHeight; 8585 PetscFunctionReturn(PETSC_SUCCESS); 8586 } 8587 8588 /*@ 8589 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8590 8591 Input Parameters: 8592 + dm - The `DMPLEX` object 8593 - cellHeight - The height of a cell 8594 8595 Level: developer 8596 8597 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8598 @*/ 8599 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8600 { 8601 DM_Plex *mesh = (DM_Plex *)dm->data; 8602 8603 PetscFunctionBegin; 8604 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8605 mesh->vtkCellHeight = cellHeight; 8606 PetscFunctionReturn(PETSC_SUCCESS); 8607 } 8608 8609 /*@ 8610 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8611 8612 Input Parameters: 8613 + dm - The `DMPLEX` object 8614 - ct - The `DMPolytopeType` of the cell 8615 8616 Output Parameters: 8617 + start - The first cell of this type, or `NULL` 8618 - end - The upper bound on this celltype, or `NULL` 8619 8620 Level: advanced 8621 8622 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8623 @*/ 8624 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8625 { 8626 DM_Plex *mesh = (DM_Plex *)dm->data; 8627 DMLabel label; 8628 PetscInt pStart, pEnd; 8629 8630 PetscFunctionBegin; 8631 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8632 if (start) { 8633 PetscAssertPointer(start, 3); 8634 *start = 0; 8635 } 8636 if (end) { 8637 PetscAssertPointer(end, 4); 8638 *end = 0; 8639 } 8640 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8641 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8642 if (mesh->tr) { 8643 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8644 } else { 8645 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8646 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8647 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8648 } 8649 PetscFunctionReturn(PETSC_SUCCESS); 8650 } 8651 8652 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8653 { 8654 PetscSection section, globalSection; 8655 PetscInt *numbers, p; 8656 8657 PetscFunctionBegin; 8658 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8659 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8660 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8661 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8662 PetscCall(PetscSectionSetUp(section)); 8663 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8664 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8665 for (p = pStart; p < pEnd; ++p) { 8666 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8667 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8668 else numbers[p - pStart] += shift; 8669 } 8670 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8671 if (globalSize) { 8672 PetscLayout layout; 8673 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8674 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8675 PetscCall(PetscLayoutDestroy(&layout)); 8676 } 8677 PetscCall(PetscSectionDestroy(§ion)); 8678 PetscCall(PetscSectionDestroy(&globalSection)); 8679 PetscFunctionReturn(PETSC_SUCCESS); 8680 } 8681 8682 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8683 { 8684 PetscInt cellHeight, cStart, cEnd; 8685 8686 PetscFunctionBegin; 8687 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8688 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8689 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8690 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8691 PetscFunctionReturn(PETSC_SUCCESS); 8692 } 8693 8694 /*@ 8695 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8696 8697 Input Parameter: 8698 . dm - The `DMPLEX` object 8699 8700 Output Parameter: 8701 . globalCellNumbers - Global cell numbers for all cells on this process 8702 8703 Level: developer 8704 8705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8706 @*/ 8707 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8708 { 8709 DM_Plex *mesh = (DM_Plex *)dm->data; 8710 8711 PetscFunctionBegin; 8712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8713 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8714 *globalCellNumbers = mesh->globalCellNumbers; 8715 PetscFunctionReturn(PETSC_SUCCESS); 8716 } 8717 8718 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8719 { 8720 PetscInt vStart, vEnd; 8721 8722 PetscFunctionBegin; 8723 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8724 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8725 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8726 PetscFunctionReturn(PETSC_SUCCESS); 8727 } 8728 8729 /*@ 8730 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8731 8732 Input Parameter: 8733 . dm - The `DMPLEX` object 8734 8735 Output Parameter: 8736 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8737 8738 Level: developer 8739 8740 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8741 @*/ 8742 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8743 { 8744 DM_Plex *mesh = (DM_Plex *)dm->data; 8745 8746 PetscFunctionBegin; 8747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8748 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8749 *globalVertexNumbers = mesh->globalVertexNumbers; 8750 PetscFunctionReturn(PETSC_SUCCESS); 8751 } 8752 8753 /*@ 8754 DMPlexCreatePointNumbering - Create a global numbering for all points. 8755 8756 Collective 8757 8758 Input Parameter: 8759 . dm - The `DMPLEX` object 8760 8761 Output Parameter: 8762 . globalPointNumbers - Global numbers for all points on this process 8763 8764 Level: developer 8765 8766 Notes: 8767 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8768 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8769 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8770 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8771 8772 The partitioned mesh is 8773 ``` 8774 (2)--0--(3)--1--(4) (1)--0--(2) 8775 ``` 8776 and its global numbering is 8777 ``` 8778 (3)--0--(4)--1--(5)--2--(6) 8779 ``` 8780 Then the global numbering is provided as 8781 ``` 8782 [0] Number of indices in set 5 8783 [0] 0 0 8784 [0] 1 1 8785 [0] 2 3 8786 [0] 3 4 8787 [0] 4 -6 8788 [1] Number of indices in set 3 8789 [1] 0 2 8790 [1] 1 5 8791 [1] 2 6 8792 ``` 8793 8794 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8795 @*/ 8796 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8797 { 8798 IS nums[4]; 8799 PetscInt depths[4], gdepths[4], starts[4]; 8800 PetscInt depth, d, shift = 0; 8801 PetscBool empty = PETSC_FALSE; 8802 8803 PetscFunctionBegin; 8804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8805 PetscCall(DMPlexGetDepth(dm, &depth)); 8806 // For unstratified meshes use dim instead of depth 8807 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8808 // If any stratum is empty, we must mark all empty 8809 for (d = 0; d <= depth; ++d) { 8810 PetscInt end; 8811 8812 depths[d] = depth - d; 8813 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8814 if (!(starts[d] - end)) empty = PETSC_TRUE; 8815 } 8816 if (empty) 8817 for (d = 0; d <= depth; ++d) { 8818 depths[d] = -1; 8819 starts[d] = -1; 8820 } 8821 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8822 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8823 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]); 8824 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8825 for (d = 0; d <= depth; ++d) { 8826 PetscInt pStart, pEnd, gsize; 8827 8828 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8829 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8830 shift += gsize; 8831 } 8832 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8833 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8834 PetscFunctionReturn(PETSC_SUCCESS); 8835 } 8836 8837 /*@ 8838 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8839 8840 Input Parameter: 8841 . dm - The `DMPLEX` object 8842 8843 Output Parameter: 8844 . ranks - The rank field 8845 8846 Options Database Key: 8847 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8848 8849 Level: intermediate 8850 8851 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8852 @*/ 8853 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8854 { 8855 DM rdm; 8856 PetscFE fe; 8857 PetscScalar *r; 8858 PetscMPIInt rank; 8859 DMPolytopeType ct; 8860 PetscInt dim, cStart, cEnd, c; 8861 PetscBool simplex; 8862 8863 PetscFunctionBeginUser; 8864 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8865 PetscAssertPointer(ranks, 2); 8866 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8867 PetscCall(DMClone(dm, &rdm)); 8868 PetscCall(DMGetDimension(rdm, &dim)); 8869 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8870 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8871 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8872 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8873 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8874 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8875 PetscCall(PetscFEDestroy(&fe)); 8876 PetscCall(DMCreateDS(rdm)); 8877 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8878 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8879 PetscCall(VecGetArray(*ranks, &r)); 8880 for (c = cStart; c < cEnd; ++c) { 8881 PetscScalar *lr; 8882 8883 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8884 if (lr) *lr = rank; 8885 } 8886 PetscCall(VecRestoreArray(*ranks, &r)); 8887 PetscCall(DMDestroy(&rdm)); 8888 PetscFunctionReturn(PETSC_SUCCESS); 8889 } 8890 8891 /*@ 8892 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8893 8894 Input Parameters: 8895 + dm - The `DMPLEX` 8896 - label - The `DMLabel` 8897 8898 Output Parameter: 8899 . val - The label value field 8900 8901 Options Database Key: 8902 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8903 8904 Level: intermediate 8905 8906 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8907 @*/ 8908 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8909 { 8910 DM rdm, plex; 8911 Vec lval; 8912 PetscSection section; 8913 PetscFE fe; 8914 PetscScalar *v; 8915 PetscInt dim, pStart, pEnd, p, cStart; 8916 DMPolytopeType ct; 8917 char name[PETSC_MAX_PATH_LEN]; 8918 const char *lname, *prefix; 8919 8920 PetscFunctionBeginUser; 8921 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8922 PetscAssertPointer(label, 2); 8923 PetscAssertPointer(val, 3); 8924 PetscCall(DMClone(dm, &rdm)); 8925 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8926 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8927 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8928 PetscCall(DMDestroy(&plex)); 8929 PetscCall(DMGetDimension(rdm, &dim)); 8930 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8931 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8932 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8933 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8934 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8935 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8936 PetscCall(PetscFEDestroy(&fe)); 8937 PetscCall(DMCreateDS(rdm)); 8938 PetscCall(DMCreateGlobalVector(rdm, val)); 8939 PetscCall(DMCreateLocalVector(rdm, &lval)); 8940 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8941 PetscCall(DMGetLocalSection(rdm, §ion)); 8942 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8943 PetscCall(VecGetArray(lval, &v)); 8944 for (p = pStart; p < pEnd; ++p) { 8945 PetscInt cval, dof, off; 8946 8947 PetscCall(PetscSectionGetDof(section, p, &dof)); 8948 if (!dof) continue; 8949 PetscCall(DMLabelGetValue(label, p, &cval)); 8950 PetscCall(PetscSectionGetOffset(section, p, &off)); 8951 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 8952 } 8953 PetscCall(VecRestoreArray(lval, &v)); 8954 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 8955 PetscCall(VecDestroy(&lval)); 8956 PetscCall(DMDestroy(&rdm)); 8957 PetscFunctionReturn(PETSC_SUCCESS); 8958 } 8959 8960 /*@ 8961 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8962 8963 Input Parameter: 8964 . dm - The `DMPLEX` object 8965 8966 Level: developer 8967 8968 Notes: 8969 This is a useful diagnostic when creating meshes programmatically. 8970 8971 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8972 8973 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8974 @*/ 8975 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8976 { 8977 PetscSection coneSection, supportSection; 8978 const PetscInt *cone, *support; 8979 PetscInt coneSize, c, supportSize, s; 8980 PetscInt pStart, pEnd, p, pp, csize, ssize; 8981 PetscBool storagecheck = PETSC_TRUE; 8982 8983 PetscFunctionBegin; 8984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8985 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8986 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8987 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8988 /* Check that point p is found in the support of its cone points, and vice versa */ 8989 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8990 for (p = pStart; p < pEnd; ++p) { 8991 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8992 PetscCall(DMPlexGetCone(dm, p, &cone)); 8993 for (c = 0; c < coneSize; ++c) { 8994 PetscBool dup = PETSC_FALSE; 8995 PetscInt d; 8996 for (d = c - 1; d >= 0; --d) { 8997 if (cone[c] == cone[d]) { 8998 dup = PETSC_TRUE; 8999 break; 9000 } 9001 } 9002 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9003 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9004 for (s = 0; s < supportSize; ++s) { 9005 if (support[s] == p) break; 9006 } 9007 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9008 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9009 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9010 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9011 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9012 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9013 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9014 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]); 9015 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9016 } 9017 } 9018 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9019 if (p != pp) { 9020 storagecheck = PETSC_FALSE; 9021 continue; 9022 } 9023 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9024 PetscCall(DMPlexGetSupport(dm, p, &support)); 9025 for (s = 0; s < supportSize; ++s) { 9026 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9027 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9028 for (c = 0; c < coneSize; ++c) { 9029 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9030 if (cone[c] != pp) { 9031 c = 0; 9032 break; 9033 } 9034 if (cone[c] == p) break; 9035 } 9036 if (c >= coneSize) { 9037 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9038 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9039 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9040 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9041 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9042 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9043 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9044 } 9045 } 9046 } 9047 if (storagecheck) { 9048 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9049 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9050 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9051 } 9052 PetscFunctionReturn(PETSC_SUCCESS); 9053 } 9054 9055 /* 9056 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. 9057 */ 9058 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9059 { 9060 DMPolytopeType cct; 9061 PetscInt ptpoints[4]; 9062 const PetscInt *cone, *ccone, *ptcone; 9063 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9064 9065 PetscFunctionBegin; 9066 *unsplit = 0; 9067 switch (ct) { 9068 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9069 ptpoints[npt++] = c; 9070 break; 9071 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9072 PetscCall(DMPlexGetCone(dm, c, &cone)); 9073 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9074 for (cp = 0; cp < coneSize; ++cp) { 9075 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9076 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9077 } 9078 break; 9079 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9080 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9081 PetscCall(DMPlexGetCone(dm, c, &cone)); 9082 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9083 for (cp = 0; cp < coneSize; ++cp) { 9084 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9085 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9086 for (ccp = 0; ccp < cconeSize; ++ccp) { 9087 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9088 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9089 PetscInt p; 9090 for (p = 0; p < npt; ++p) 9091 if (ptpoints[p] == ccone[ccp]) break; 9092 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9093 } 9094 } 9095 } 9096 break; 9097 default: 9098 break; 9099 } 9100 for (pt = 0; pt < npt; ++pt) { 9101 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9102 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9103 } 9104 PetscFunctionReturn(PETSC_SUCCESS); 9105 } 9106 9107 /*@ 9108 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9109 9110 Input Parameters: 9111 + dm - The `DMPLEX` object 9112 - cellHeight - Normally 0 9113 9114 Level: developer 9115 9116 Notes: 9117 This is a useful diagnostic when creating meshes programmatically. 9118 Currently applicable only to homogeneous simplex or tensor meshes. 9119 9120 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9121 9122 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9123 @*/ 9124 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9125 { 9126 DMPlexInterpolatedFlag interp; 9127 DMPolytopeType ct; 9128 PetscInt vStart, vEnd, cStart, cEnd, c; 9129 9130 PetscFunctionBegin; 9131 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9132 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9133 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9135 for (c = cStart; c < cEnd; ++c) { 9136 PetscInt *closure = NULL; 9137 PetscInt coneSize, closureSize, cl, Nv = 0; 9138 9139 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9140 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9141 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9142 if (interp == DMPLEX_INTERPOLATED_FULL) { 9143 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9144 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)); 9145 } 9146 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9147 for (cl = 0; cl < closureSize * 2; cl += 2) { 9148 const PetscInt p = closure[cl]; 9149 if ((p >= vStart) && (p < vEnd)) ++Nv; 9150 } 9151 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9152 /* Special Case: Tensor faces with identified vertices */ 9153 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9154 PetscInt unsplit; 9155 9156 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9157 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9158 } 9159 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)); 9160 } 9161 PetscFunctionReturn(PETSC_SUCCESS); 9162 } 9163 9164 /*@ 9165 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9166 9167 Collective 9168 9169 Input Parameters: 9170 + dm - The `DMPLEX` object 9171 - cellHeight - Normally 0 9172 9173 Level: developer 9174 9175 Notes: 9176 This is a useful diagnostic when creating meshes programmatically. 9177 This routine is only relevant for meshes that are fully interpolated across all ranks. 9178 It will error out if a partially interpolated mesh is given on some rank. 9179 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9180 9181 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9182 9183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9184 @*/ 9185 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9186 { 9187 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9188 DMPlexInterpolatedFlag interpEnum; 9189 9190 PetscFunctionBegin; 9191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9192 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9193 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9194 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9195 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9196 PetscFunctionReturn(PETSC_SUCCESS); 9197 } 9198 9199 PetscCall(DMGetDimension(dm, &dim)); 9200 PetscCall(DMPlexGetDepth(dm, &depth)); 9201 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9202 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9203 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9204 for (c = cStart; c < cEnd; ++c) { 9205 const PetscInt *cone, *ornt, *faceSizes, *faces; 9206 const DMPolytopeType *faceTypes; 9207 DMPolytopeType ct; 9208 PetscInt numFaces, coneSize, f; 9209 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9210 9211 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9212 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9213 if (unsplit) continue; 9214 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9215 PetscCall(DMPlexGetCone(dm, c, &cone)); 9216 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9217 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9218 for (cl = 0; cl < closureSize * 2; cl += 2) { 9219 const PetscInt p = closure[cl]; 9220 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9221 } 9222 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9223 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); 9224 for (f = 0; f < numFaces; ++f) { 9225 DMPolytopeType fct; 9226 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9227 9228 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9229 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9230 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9231 const PetscInt p = fclosure[cl]; 9232 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9233 } 9234 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]); 9235 for (v = 0; v < fnumCorners; ++v) { 9236 if (fclosure[v] != faces[fOff + v]) { 9237 PetscInt v1; 9238 9239 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9240 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9241 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9242 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9243 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9244 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]); 9245 } 9246 } 9247 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9248 fOff += faceSizes[f]; 9249 } 9250 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9251 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9252 } 9253 } 9254 PetscFunctionReturn(PETSC_SUCCESS); 9255 } 9256 9257 /*@ 9258 DMPlexCheckGeometry - Check the geometry of mesh cells 9259 9260 Input Parameter: 9261 . dm - The `DMPLEX` object 9262 9263 Level: developer 9264 9265 Notes: 9266 This is a useful diagnostic when creating meshes programmatically. 9267 9268 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9269 9270 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9271 @*/ 9272 PetscErrorCode DMPlexCheckGeometry(DM dm) 9273 { 9274 Vec coordinates; 9275 PetscReal detJ, J[9], refVol = 1.0; 9276 PetscReal vol; 9277 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9278 9279 PetscFunctionBegin; 9280 PetscCall(DMGetDimension(dm, &dim)); 9281 PetscCall(DMGetCoordinateDim(dm, &dE)); 9282 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9283 PetscCall(DMPlexGetDepth(dm, &depth)); 9284 for (d = 0; d < dim; ++d) refVol *= 2.0; 9285 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9286 /* Make sure local coordinates are created, because that step is collective */ 9287 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9288 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9289 for (c = cStart; c < cEnd; ++c) { 9290 DMPolytopeType ct; 9291 PetscInt unsplit; 9292 PetscBool ignoreZeroVol = PETSC_FALSE; 9293 9294 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9295 switch (ct) { 9296 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9297 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9298 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9299 ignoreZeroVol = PETSC_TRUE; 9300 break; 9301 default: 9302 break; 9303 } 9304 switch (ct) { 9305 case DM_POLYTOPE_TRI_PRISM: 9306 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9307 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9308 case DM_POLYTOPE_PYRAMID: 9309 continue; 9310 default: 9311 break; 9312 } 9313 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9314 if (unsplit) continue; 9315 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9316 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); 9317 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9318 /* This should work with periodicity since DG coordinates should be used */ 9319 if (depth > 1) { 9320 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9321 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); 9322 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9323 } 9324 } 9325 PetscFunctionReturn(PETSC_SUCCESS); 9326 } 9327 9328 /*@ 9329 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9330 9331 Collective 9332 9333 Input Parameters: 9334 + dm - The `DMPLEX` object 9335 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9336 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9337 9338 Level: developer 9339 9340 Notes: 9341 This is mainly intended for debugging/testing purposes. 9342 9343 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9344 9345 Extra roots can come from periodic cuts, where additional points appear on the boundary 9346 9347 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9348 @*/ 9349 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9350 { 9351 PetscInt l, nleaves, nroots, overlap; 9352 const PetscInt *locals; 9353 const PetscSFNode *remotes; 9354 PetscBool distributed; 9355 MPI_Comm comm; 9356 PetscMPIInt rank; 9357 9358 PetscFunctionBegin; 9359 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9360 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9361 else pointSF = dm->sf; 9362 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9363 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9364 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9365 { 9366 PetscMPIInt mpiFlag; 9367 9368 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9369 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9370 } 9371 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9372 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9373 if (!distributed) { 9374 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); 9375 PetscFunctionReturn(PETSC_SUCCESS); 9376 } 9377 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); 9378 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9379 9380 /* Check SF graph is compatible with DMPlex chart */ 9381 { 9382 PetscInt pStart, pEnd, maxLeaf; 9383 9384 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9385 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9386 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9387 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9388 } 9389 9390 /* Check Point SF has no local points referenced */ 9391 for (l = 0; l < nleaves; l++) { 9392 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); 9393 } 9394 9395 /* Check there are no cells in interface */ 9396 if (!overlap) { 9397 PetscInt cellHeight, cStart, cEnd; 9398 9399 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9400 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9401 for (l = 0; l < nleaves; ++l) { 9402 const PetscInt point = locals ? locals[l] : l; 9403 9404 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9405 } 9406 } 9407 9408 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9409 { 9410 const PetscInt *rootdegree; 9411 9412 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9413 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9414 for (l = 0; l < nleaves; ++l) { 9415 const PetscInt point = locals ? locals[l] : l; 9416 const PetscInt *cone; 9417 PetscInt coneSize, c, idx; 9418 9419 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9420 PetscCall(DMPlexGetCone(dm, point, &cone)); 9421 for (c = 0; c < coneSize; ++c) { 9422 if (!rootdegree[cone[c]]) { 9423 if (locals) { 9424 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9425 } else { 9426 idx = (cone[c] < nleaves) ? cone[c] : -1; 9427 } 9428 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9429 } 9430 } 9431 } 9432 } 9433 PetscFunctionReturn(PETSC_SUCCESS); 9434 } 9435 9436 /*@ 9437 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9438 9439 Collective 9440 9441 Input Parameter: 9442 . dm - The `DMPLEX` object 9443 9444 Level: developer 9445 9446 Notes: 9447 This is mainly intended for debugging/testing purposes. 9448 9449 Other cell types which are disconnected would be caught by the symmetry and face checks. 9450 9451 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9452 9453 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9454 @*/ 9455 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9456 { 9457 PetscInt pStart, pEnd, vStart, vEnd; 9458 9459 PetscFunctionBegin; 9460 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9461 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9462 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9463 for (PetscInt v = vStart; v < vEnd; ++v) { 9464 PetscInt suppSize; 9465 9466 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9467 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9468 } 9469 PetscFunctionReturn(PETSC_SUCCESS); 9470 } 9471 9472 /*@ 9473 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9474 9475 Input Parameter: 9476 . dm - The `DMPLEX` object 9477 9478 Level: developer 9479 9480 Notes: 9481 This is a useful diagnostic when creating meshes programmatically. 9482 9483 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9484 9485 Currently does not include `DMPlexCheckCellShape()`. 9486 9487 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9488 @*/ 9489 PetscErrorCode DMPlexCheck(DM dm) 9490 { 9491 PetscInt cellHeight; 9492 9493 PetscFunctionBegin; 9494 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9495 PetscCall(DMPlexCheckSymmetry(dm)); 9496 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9497 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9498 PetscCall(DMPlexCheckGeometry(dm)); 9499 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9500 PetscCall(DMPlexCheckInterfaceCones(dm)); 9501 PetscCall(DMPlexCheckOrphanVertices(dm)); 9502 PetscFunctionReturn(PETSC_SUCCESS); 9503 } 9504 9505 typedef struct cell_stats { 9506 PetscReal min, max, sum, squaresum; 9507 PetscInt count; 9508 } cell_stats_t; 9509 9510 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9511 { 9512 PetscInt i, N = *len; 9513 9514 for (i = 0; i < N; i++) { 9515 cell_stats_t *A = (cell_stats_t *)a; 9516 cell_stats_t *B = (cell_stats_t *)b; 9517 9518 B->min = PetscMin(A->min, B->min); 9519 B->max = PetscMax(A->max, B->max); 9520 B->sum += A->sum; 9521 B->squaresum += A->squaresum; 9522 B->count += A->count; 9523 } 9524 } 9525 9526 /*@ 9527 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9528 9529 Collective 9530 9531 Input Parameters: 9532 + dm - The `DMPLEX` object 9533 . output - If true, statistics will be displayed on `stdout` 9534 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9535 9536 Level: developer 9537 9538 Notes: 9539 This is mainly intended for debugging/testing purposes. 9540 9541 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9542 9543 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9544 @*/ 9545 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9546 { 9547 DM dmCoarse; 9548 cell_stats_t stats, globalStats; 9549 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9550 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9551 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9552 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9553 PetscMPIInt rank, size; 9554 9555 PetscFunctionBegin; 9556 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9557 stats.min = PETSC_MAX_REAL; 9558 stats.max = PETSC_MIN_REAL; 9559 stats.sum = stats.squaresum = 0.; 9560 stats.count = 0; 9561 9562 PetscCallMPI(MPI_Comm_size(comm, &size)); 9563 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9564 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9565 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9566 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9567 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9568 for (c = cStart; c < cEnd; c++) { 9569 PetscInt i; 9570 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9571 9572 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9573 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9574 for (i = 0; i < PetscSqr(cdim); ++i) { 9575 frobJ += J[i] * J[i]; 9576 frobInvJ += invJ[i] * invJ[i]; 9577 } 9578 cond2 = frobJ * frobInvJ; 9579 cond = PetscSqrtReal(cond2); 9580 9581 stats.min = PetscMin(stats.min, cond); 9582 stats.max = PetscMax(stats.max, cond); 9583 stats.sum += cond; 9584 stats.squaresum += cond2; 9585 stats.count++; 9586 if (output && cond > limit) { 9587 PetscSection coordSection; 9588 Vec coordsLocal; 9589 PetscScalar *coords = NULL; 9590 PetscInt Nv, d, clSize, cl, *closure = NULL; 9591 9592 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9593 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9594 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9595 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9596 for (i = 0; i < Nv / cdim; ++i) { 9597 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9598 for (d = 0; d < cdim; ++d) { 9599 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9600 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9601 } 9602 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9603 } 9604 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9605 for (cl = 0; cl < clSize * 2; cl += 2) { 9606 const PetscInt edge = closure[cl]; 9607 9608 if ((edge >= eStart) && (edge < eEnd)) { 9609 PetscReal len; 9610 9611 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9612 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9613 } 9614 } 9615 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9616 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9617 } 9618 } 9619 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9620 9621 if (size > 1) { 9622 PetscMPIInt blockLengths[2] = {4, 1}; 9623 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9624 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9625 MPI_Op statReduce; 9626 9627 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9628 PetscCallMPI(MPI_Type_commit(&statType)); 9629 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9630 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9631 PetscCallMPI(MPI_Op_free(&statReduce)); 9632 PetscCallMPI(MPI_Type_free(&statType)); 9633 } else { 9634 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9635 } 9636 if (rank == 0) { 9637 count = globalStats.count; 9638 min = globalStats.min; 9639 max = globalStats.max; 9640 mean = globalStats.sum / globalStats.count; 9641 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9642 } 9643 9644 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)); 9645 PetscCall(PetscFree2(J, invJ)); 9646 9647 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9648 if (dmCoarse) { 9649 PetscBool isplex; 9650 9651 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9652 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9653 } 9654 PetscFunctionReturn(PETSC_SUCCESS); 9655 } 9656 9657 /*@ 9658 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9659 orthogonal quality below given tolerance. 9660 9661 Collective 9662 9663 Input Parameters: 9664 + dm - The `DMPLEX` object 9665 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9666 - atol - [0, 1] Absolute tolerance for tagging cells. 9667 9668 Output Parameters: 9669 + OrthQual - `Vec` containing orthogonal quality per cell 9670 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9671 9672 Options Database Keys: 9673 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9674 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9675 9676 Level: intermediate 9677 9678 Notes: 9679 Orthogonal quality is given by the following formula\: 9680 9681 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9682 9683 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 9684 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9685 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9686 calculating the cosine of the angle between these vectors. 9687 9688 Orthogonal quality ranges from 1 (best) to 0 (worst). 9689 9690 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9691 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9692 9693 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9694 9695 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9696 @*/ 9697 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9698 { 9699 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9700 PetscInt *idx; 9701 PetscScalar *oqVals; 9702 const PetscScalar *cellGeomArr, *faceGeomArr; 9703 PetscReal *ci, *fi, *Ai; 9704 MPI_Comm comm; 9705 Vec cellgeom, facegeom; 9706 DM dmFace, dmCell; 9707 IS glob; 9708 ISLocalToGlobalMapping ltog; 9709 PetscViewer vwr; 9710 9711 PetscFunctionBegin; 9712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9713 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9714 PetscAssertPointer(OrthQual, 4); 9715 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9716 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9717 PetscCall(DMGetDimension(dm, &nc)); 9718 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9719 { 9720 DMPlexInterpolatedFlag interpFlag; 9721 9722 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9723 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9724 PetscMPIInt rank; 9725 9726 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9727 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9728 } 9729 } 9730 if (OrthQualLabel) { 9731 PetscAssertPointer(OrthQualLabel, 5); 9732 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9733 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9734 } else { 9735 *OrthQualLabel = NULL; 9736 } 9737 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9738 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9739 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9740 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9741 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9742 PetscCall(VecCreate(comm, OrthQual)); 9743 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9744 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9745 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9746 PetscCall(VecSetUp(*OrthQual)); 9747 PetscCall(ISDestroy(&glob)); 9748 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9749 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9750 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9751 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9752 PetscCall(VecGetDM(cellgeom, &dmCell)); 9753 PetscCall(VecGetDM(facegeom, &dmFace)); 9754 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9755 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9756 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9757 PetscInt cellarr[2], *adj = NULL; 9758 PetscScalar *cArr, *fArr; 9759 PetscReal minvalc = 1.0, minvalf = 1.0; 9760 PetscFVCellGeom *cg; 9761 9762 idx[cellIter] = cell - cStart; 9763 cellarr[0] = cell; 9764 /* Make indexing into cellGeom easier */ 9765 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9766 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9767 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9768 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9769 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9770 PetscInt i; 9771 const PetscInt neigh = adj[cellneigh]; 9772 PetscReal normci = 0, normfi = 0, normai = 0; 9773 PetscFVCellGeom *cgneigh; 9774 PetscFVFaceGeom *fg; 9775 9776 /* Don't count ourselves in the neighbor list */ 9777 if (neigh == cell) continue; 9778 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9779 cellarr[1] = neigh; 9780 { 9781 PetscInt numcovpts; 9782 const PetscInt *covpts; 9783 9784 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9785 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9786 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9787 } 9788 9789 /* Compute c_i, f_i and their norms */ 9790 for (i = 0; i < nc; i++) { 9791 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9792 fi[i] = fg->centroid[i] - cg->centroid[i]; 9793 Ai[i] = fg->normal[i]; 9794 normci += PetscPowReal(ci[i], 2); 9795 normfi += PetscPowReal(fi[i], 2); 9796 normai += PetscPowReal(Ai[i], 2); 9797 } 9798 normci = PetscSqrtReal(normci); 9799 normfi = PetscSqrtReal(normfi); 9800 normai = PetscSqrtReal(normai); 9801 9802 /* Normalize and compute for each face-cell-normal pair */ 9803 for (i = 0; i < nc; i++) { 9804 ci[i] = ci[i] / normci; 9805 fi[i] = fi[i] / normfi; 9806 Ai[i] = Ai[i] / normai; 9807 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9808 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9809 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9810 } 9811 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9812 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9813 } 9814 PetscCall(PetscFree(adj)); 9815 PetscCall(PetscFree2(cArr, fArr)); 9816 /* Defer to cell if they're equal */ 9817 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9818 if (OrthQualLabel) { 9819 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9820 } 9821 } 9822 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9823 PetscCall(VecAssemblyBegin(*OrthQual)); 9824 PetscCall(VecAssemblyEnd(*OrthQual)); 9825 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9826 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9827 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9828 if (OrthQualLabel) { 9829 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9830 } 9831 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9832 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9833 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9834 PetscFunctionReturn(PETSC_SUCCESS); 9835 } 9836 9837 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9838 * interpolator construction */ 9839 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9840 { 9841 PetscSection section, newSection, gsection; 9842 PetscSF sf; 9843 PetscBool hasConstraints, ghasConstraints; 9844 9845 PetscFunctionBegin; 9846 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9847 PetscAssertPointer(odm, 2); 9848 PetscCall(DMGetLocalSection(dm, §ion)); 9849 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9850 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9851 if (!ghasConstraints) { 9852 PetscCall(PetscObjectReference((PetscObject)dm)); 9853 *odm = dm; 9854 PetscFunctionReturn(PETSC_SUCCESS); 9855 } 9856 PetscCall(DMClone(dm, odm)); 9857 PetscCall(DMCopyFields(dm, *odm)); 9858 PetscCall(DMGetLocalSection(*odm, &newSection)); 9859 PetscCall(DMGetPointSF(*odm, &sf)); 9860 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9861 PetscCall(DMSetGlobalSection(*odm, gsection)); 9862 PetscCall(PetscSectionDestroy(&gsection)); 9863 PetscFunctionReturn(PETSC_SUCCESS); 9864 } 9865 9866 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9867 { 9868 DM dmco, dmfo; 9869 Mat interpo; 9870 Vec rscale; 9871 Vec cglobalo, clocal; 9872 Vec fglobal, fglobalo, flocal; 9873 PetscBool regular; 9874 9875 PetscFunctionBegin; 9876 PetscCall(DMGetFullDM(dmc, &dmco)); 9877 PetscCall(DMGetFullDM(dmf, &dmfo)); 9878 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9879 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9880 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9881 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9882 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9883 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9884 PetscCall(VecSet(cglobalo, 0.)); 9885 PetscCall(VecSet(clocal, 0.)); 9886 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9887 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9888 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9889 PetscCall(VecSet(fglobal, 0.)); 9890 PetscCall(VecSet(fglobalo, 0.)); 9891 PetscCall(VecSet(flocal, 0.)); 9892 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9893 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9894 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9895 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9896 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9897 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9898 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9899 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9900 *shift = fglobal; 9901 PetscCall(VecDestroy(&flocal)); 9902 PetscCall(VecDestroy(&fglobalo)); 9903 PetscCall(VecDestroy(&clocal)); 9904 PetscCall(VecDestroy(&cglobalo)); 9905 PetscCall(VecDestroy(&rscale)); 9906 PetscCall(MatDestroy(&interpo)); 9907 PetscCall(DMDestroy(&dmfo)); 9908 PetscCall(DMDestroy(&dmco)); 9909 PetscFunctionReturn(PETSC_SUCCESS); 9910 } 9911 9912 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9913 { 9914 PetscObject shifto; 9915 Vec shift; 9916 9917 PetscFunctionBegin; 9918 if (!interp) { 9919 Vec rscale; 9920 9921 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9922 PetscCall(VecDestroy(&rscale)); 9923 } else { 9924 PetscCall(PetscObjectReference((PetscObject)interp)); 9925 } 9926 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9927 if (!shifto) { 9928 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9929 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9930 shifto = (PetscObject)shift; 9931 PetscCall(VecDestroy(&shift)); 9932 } 9933 shift = (Vec)shifto; 9934 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9935 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9936 PetscCall(MatDestroy(&interp)); 9937 PetscFunctionReturn(PETSC_SUCCESS); 9938 } 9939 9940 /* Pointwise interpolation 9941 Just code FEM for now 9942 u^f = I u^c 9943 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9944 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9945 I_{ij} = psi^f_i phi^c_j 9946 */ 9947 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9948 { 9949 PetscSection gsc, gsf; 9950 PetscInt m, n; 9951 void *ctx; 9952 DM cdm; 9953 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9954 9955 PetscFunctionBegin; 9956 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9957 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9958 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9959 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9960 9961 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9962 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9963 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9964 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9965 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9966 9967 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9968 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9969 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9970 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9971 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9972 if (scaling) { 9973 /* Use naive scaling */ 9974 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9975 } 9976 PetscFunctionReturn(PETSC_SUCCESS); 9977 } 9978 9979 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9980 { 9981 VecScatter ctx; 9982 9983 PetscFunctionBegin; 9984 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9985 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9986 PetscCall(VecScatterDestroy(&ctx)); 9987 PetscFunctionReturn(PETSC_SUCCESS); 9988 } 9989 9990 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[]) 9991 { 9992 const PetscInt Nc = uOff[1] - uOff[0]; 9993 PetscInt c; 9994 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9995 } 9996 9997 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9998 { 9999 DM dmc; 10000 PetscDS ds; 10001 Vec ones, locmass; 10002 IS cellIS; 10003 PetscFormKey key; 10004 PetscInt depth; 10005 10006 PetscFunctionBegin; 10007 PetscCall(DMClone(dm, &dmc)); 10008 PetscCall(DMCopyDisc(dm, dmc)); 10009 PetscCall(DMGetDS(dmc, &ds)); 10010 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10011 PetscCall(DMCreateGlobalVector(dmc, mass)); 10012 PetscCall(DMGetLocalVector(dmc, &ones)); 10013 PetscCall(DMGetLocalVector(dmc, &locmass)); 10014 PetscCall(DMPlexGetDepth(dmc, &depth)); 10015 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10016 PetscCall(VecSet(locmass, 0.0)); 10017 PetscCall(VecSet(ones, 1.0)); 10018 key.label = NULL; 10019 key.value = 0; 10020 key.field = 0; 10021 key.part = 0; 10022 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10023 PetscCall(ISDestroy(&cellIS)); 10024 PetscCall(VecSet(*mass, 0.0)); 10025 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 10026 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 10027 PetscCall(DMRestoreLocalVector(dmc, &ones)); 10028 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 10029 PetscCall(DMDestroy(&dmc)); 10030 PetscFunctionReturn(PETSC_SUCCESS); 10031 } 10032 10033 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10034 { 10035 PetscSection gsc, gsf; 10036 PetscInt m, n; 10037 void *ctx; 10038 DM cdm; 10039 PetscBool regular; 10040 10041 PetscFunctionBegin; 10042 if (dmFine == dmCoarse) { 10043 DM dmc; 10044 PetscDS ds; 10045 PetscWeakForm wf; 10046 Vec u; 10047 IS cellIS; 10048 PetscFormKey key; 10049 PetscInt depth; 10050 10051 PetscCall(DMClone(dmFine, &dmc)); 10052 PetscCall(DMCopyDisc(dmFine, dmc)); 10053 PetscCall(DMGetDS(dmc, &ds)); 10054 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10055 PetscCall(PetscWeakFormClear(wf)); 10056 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10057 PetscCall(DMCreateMatrix(dmc, mass)); 10058 PetscCall(DMGetLocalVector(dmc, &u)); 10059 PetscCall(DMPlexGetDepth(dmc, &depth)); 10060 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10061 PetscCall(MatZeroEntries(*mass)); 10062 key.label = NULL; 10063 key.value = 0; 10064 key.field = 0; 10065 key.part = 0; 10066 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10067 PetscCall(ISDestroy(&cellIS)); 10068 PetscCall(DMRestoreLocalVector(dmc, &u)); 10069 PetscCall(DMDestroy(&dmc)); 10070 } else { 10071 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10072 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10073 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10074 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10075 10076 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10077 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10078 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10079 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10080 10081 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10082 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10083 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10084 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10085 } 10086 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10087 PetscFunctionReturn(PETSC_SUCCESS); 10088 } 10089 10090 /*@ 10091 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10092 10093 Input Parameter: 10094 . dm - The `DMPLEX` object 10095 10096 Output Parameter: 10097 . regular - The flag 10098 10099 Level: intermediate 10100 10101 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10102 @*/ 10103 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10104 { 10105 PetscFunctionBegin; 10106 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10107 PetscAssertPointer(regular, 2); 10108 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10109 PetscFunctionReturn(PETSC_SUCCESS); 10110 } 10111 10112 /*@ 10113 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10114 10115 Input Parameters: 10116 + dm - The `DMPLEX` object 10117 - regular - The flag 10118 10119 Level: intermediate 10120 10121 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10122 @*/ 10123 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10124 { 10125 PetscFunctionBegin; 10126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10127 ((DM_Plex *)dm->data)->regularRefinement = regular; 10128 PetscFunctionReturn(PETSC_SUCCESS); 10129 } 10130 10131 /*@ 10132 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10133 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10134 10135 Not Collective 10136 10137 Input Parameter: 10138 . dm - The `DMPLEX` object 10139 10140 Output Parameters: 10141 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10142 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10143 10144 Level: intermediate 10145 10146 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10147 @*/ 10148 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10149 { 10150 DM_Plex *plex = (DM_Plex *)dm->data; 10151 10152 PetscFunctionBegin; 10153 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10154 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10155 if (anchorSection) *anchorSection = plex->anchorSection; 10156 if (anchorIS) *anchorIS = plex->anchorIS; 10157 PetscFunctionReturn(PETSC_SUCCESS); 10158 } 10159 10160 /*@ 10161 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10162 10163 Collective 10164 10165 Input Parameters: 10166 + dm - The `DMPLEX` object 10167 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10168 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10169 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10170 10171 Level: intermediate 10172 10173 Notes: 10174 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10175 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10176 combination of other points' degrees of freedom. 10177 10178 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10179 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10180 10181 The reference counts of `anchorSection` and `anchorIS` are incremented. 10182 10183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10184 @*/ 10185 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10186 { 10187 DM_Plex *plex = (DM_Plex *)dm->data; 10188 PetscMPIInt result; 10189 10190 PetscFunctionBegin; 10191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10192 if (anchorSection) { 10193 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10194 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10195 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10196 } 10197 if (anchorIS) { 10198 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10199 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10200 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10201 } 10202 10203 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10204 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10205 plex->anchorSection = anchorSection; 10206 10207 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10208 PetscCall(ISDestroy(&plex->anchorIS)); 10209 plex->anchorIS = anchorIS; 10210 10211 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10212 PetscInt size, a, pStart, pEnd; 10213 const PetscInt *anchors; 10214 10215 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10216 PetscCall(ISGetLocalSize(anchorIS, &size)); 10217 PetscCall(ISGetIndices(anchorIS, &anchors)); 10218 for (a = 0; a < size; a++) { 10219 PetscInt p; 10220 10221 p = anchors[a]; 10222 if (p >= pStart && p < pEnd) { 10223 PetscInt dof; 10224 10225 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10226 if (dof) { 10227 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10228 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10229 } 10230 } 10231 } 10232 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10233 } 10234 /* reset the generic constraints */ 10235 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10236 PetscFunctionReturn(PETSC_SUCCESS); 10237 } 10238 10239 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10240 { 10241 PetscSection anchorSection; 10242 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10243 10244 PetscFunctionBegin; 10245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10246 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10247 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10248 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10249 if (numFields) { 10250 PetscInt f; 10251 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10252 10253 for (f = 0; f < numFields; f++) { 10254 PetscInt numComp; 10255 10256 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10257 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10258 } 10259 } 10260 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10261 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10262 pStart = PetscMax(pStart, sStart); 10263 pEnd = PetscMin(pEnd, sEnd); 10264 pEnd = PetscMax(pStart, pEnd); 10265 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10266 for (p = pStart; p < pEnd; p++) { 10267 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10268 if (dof) { 10269 PetscCall(PetscSectionGetDof(section, p, &dof)); 10270 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10271 for (f = 0; f < numFields; f++) { 10272 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10273 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10274 } 10275 } 10276 } 10277 PetscCall(PetscSectionSetUp(*cSec)); 10278 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10279 PetscFunctionReturn(PETSC_SUCCESS); 10280 } 10281 10282 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10283 { 10284 PetscSection aSec; 10285 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10286 const PetscInt *anchors; 10287 PetscInt numFields, f; 10288 IS aIS; 10289 MatType mtype; 10290 PetscBool iscuda, iskokkos; 10291 10292 PetscFunctionBegin; 10293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10294 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10295 PetscCall(PetscSectionGetStorageSize(section, &n)); 10296 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10297 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10298 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10299 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10300 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10301 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10302 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10303 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10304 else mtype = MATSEQAIJ; 10305 PetscCall(MatSetType(*cMat, mtype)); 10306 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10307 PetscCall(ISGetIndices(aIS, &anchors)); 10308 /* cSec will be a subset of aSec and section */ 10309 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10310 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10311 PetscCall(PetscMalloc1(m + 1, &i)); 10312 i[0] = 0; 10313 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10314 for (p = pStart; p < pEnd; p++) { 10315 PetscInt rDof, rOff, r; 10316 10317 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10318 if (!rDof) continue; 10319 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10320 if (numFields) { 10321 for (f = 0; f < numFields; f++) { 10322 annz = 0; 10323 for (r = 0; r < rDof; r++) { 10324 a = anchors[rOff + r]; 10325 if (a < sStart || a >= sEnd) continue; 10326 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10327 annz += aDof; 10328 } 10329 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10330 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10331 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10332 } 10333 } else { 10334 annz = 0; 10335 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10336 for (q = 0; q < dof; q++) { 10337 a = anchors[rOff + q]; 10338 if (a < sStart || a >= sEnd) continue; 10339 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10340 annz += aDof; 10341 } 10342 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10343 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10344 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10345 } 10346 } 10347 nnz = i[m]; 10348 PetscCall(PetscMalloc1(nnz, &j)); 10349 offset = 0; 10350 for (p = pStart; p < pEnd; p++) { 10351 if (numFields) { 10352 for (f = 0; f < numFields; f++) { 10353 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10354 for (q = 0; q < dof; q++) { 10355 PetscInt rDof, rOff, r; 10356 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10357 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10358 for (r = 0; r < rDof; r++) { 10359 PetscInt s; 10360 10361 a = anchors[rOff + r]; 10362 if (a < sStart || a >= sEnd) continue; 10363 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10364 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10365 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10366 } 10367 } 10368 } 10369 } else { 10370 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10371 for (q = 0; q < dof; q++) { 10372 PetscInt rDof, rOff, r; 10373 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10374 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10375 for (r = 0; r < rDof; r++) { 10376 PetscInt s; 10377 10378 a = anchors[rOff + r]; 10379 if (a < sStart || a >= sEnd) continue; 10380 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10381 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10382 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10383 } 10384 } 10385 } 10386 } 10387 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10388 PetscCall(PetscFree(i)); 10389 PetscCall(PetscFree(j)); 10390 PetscCall(ISRestoreIndices(aIS, &anchors)); 10391 PetscFunctionReturn(PETSC_SUCCESS); 10392 } 10393 10394 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10395 { 10396 DM_Plex *plex = (DM_Plex *)dm->data; 10397 PetscSection anchorSection, section, cSec; 10398 Mat cMat; 10399 10400 PetscFunctionBegin; 10401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10402 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10403 if (anchorSection) { 10404 PetscInt Nf; 10405 10406 PetscCall(DMGetLocalSection(dm, §ion)); 10407 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10408 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10409 PetscCall(DMGetNumFields(dm, &Nf)); 10410 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10411 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10412 PetscCall(PetscSectionDestroy(&cSec)); 10413 PetscCall(MatDestroy(&cMat)); 10414 } 10415 PetscFunctionReturn(PETSC_SUCCESS); 10416 } 10417 10418 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10419 { 10420 IS subis; 10421 PetscSection section, subsection; 10422 10423 PetscFunctionBegin; 10424 PetscCall(DMGetLocalSection(dm, §ion)); 10425 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10426 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10427 /* Create subdomain */ 10428 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10429 /* Create submodel */ 10430 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10431 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10432 PetscCall(DMSetLocalSection(*subdm, subsection)); 10433 PetscCall(PetscSectionDestroy(&subsection)); 10434 PetscCall(DMCopyDisc(dm, *subdm)); 10435 /* Create map from submodel to global model */ 10436 if (is) { 10437 PetscSection sectionGlobal, subsectionGlobal; 10438 IS spIS; 10439 const PetscInt *spmap; 10440 PetscInt *subIndices; 10441 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10442 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10443 10444 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10445 PetscCall(ISGetIndices(spIS, &spmap)); 10446 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10447 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10448 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10449 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10450 for (p = pStart; p < pEnd; ++p) { 10451 PetscInt gdof, pSubSize = 0; 10452 10453 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10454 if (gdof > 0) { 10455 for (f = 0; f < Nf; ++f) { 10456 PetscInt fdof, fcdof; 10457 10458 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10459 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10460 pSubSize += fdof - fcdof; 10461 } 10462 subSize += pSubSize; 10463 if (pSubSize) { 10464 if (bs < 0) { 10465 bs = pSubSize; 10466 } else if (bs != pSubSize) { 10467 /* Layout does not admit a pointwise block size */ 10468 bs = 1; 10469 } 10470 } 10471 } 10472 } 10473 /* Must have same blocksize on all procs (some might have no points) */ 10474 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10475 bsLocal[1] = bs; 10476 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10477 if (bsMinMax[0] != bsMinMax[1]) { 10478 bs = 1; 10479 } else { 10480 bs = bsMinMax[0]; 10481 } 10482 PetscCall(PetscMalloc1(subSize, &subIndices)); 10483 for (p = pStart; p < pEnd; ++p) { 10484 PetscInt gdof, goff; 10485 10486 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10487 if (gdof > 0) { 10488 const PetscInt point = spmap[p]; 10489 10490 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10491 for (f = 0; f < Nf; ++f) { 10492 PetscInt fdof, fcdof, fc, f2, poff = 0; 10493 10494 /* Can get rid of this loop by storing field information in the global section */ 10495 for (f2 = 0; f2 < f; ++f2) { 10496 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10497 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10498 poff += fdof - fcdof; 10499 } 10500 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10501 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10502 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10503 } 10504 } 10505 } 10506 PetscCall(ISRestoreIndices(spIS, &spmap)); 10507 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10508 if (bs > 1) { 10509 /* We need to check that the block size does not come from non-contiguous fields */ 10510 PetscInt i, j, set = 1; 10511 for (i = 0; i < subSize; i += bs) { 10512 for (j = 0; j < bs; ++j) { 10513 if (subIndices[i + j] != subIndices[i] + j) { 10514 set = 0; 10515 break; 10516 } 10517 } 10518 } 10519 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10520 } 10521 /* Attach nullspace */ 10522 for (f = 0; f < Nf; ++f) { 10523 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10524 if ((*subdm)->nullspaceConstructors[f]) break; 10525 } 10526 if (f < Nf) { 10527 MatNullSpace nullSpace; 10528 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10529 10530 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10531 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10532 } 10533 } 10534 PetscFunctionReturn(PETSC_SUCCESS); 10535 } 10536 10537 /*@ 10538 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10539 10540 Input Parameters: 10541 + dm - The `DM` 10542 - dummy - unused argument 10543 10544 Options Database Key: 10545 . -dm_plex_monitor_throughput - Activate the monitor 10546 10547 Level: developer 10548 10549 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10550 @*/ 10551 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10552 { 10553 PetscLogHandler default_handler; 10554 10555 PetscFunctionBegin; 10556 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10557 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10558 if (default_handler) { 10559 PetscLogEvent event; 10560 PetscEventPerfInfo eventInfo; 10561 PetscReal cellRate, flopRate; 10562 PetscInt cStart, cEnd, Nf, N; 10563 const char *name; 10564 10565 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10566 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10567 PetscCall(DMGetNumFields(dm, &Nf)); 10568 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10569 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10570 N = (cEnd - cStart) * Nf * eventInfo.count; 10571 flopRate = eventInfo.flops / eventInfo.time; 10572 cellRate = N / eventInfo.time; 10573 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))); 10574 } else { 10575 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."); 10576 } 10577 PetscFunctionReturn(PETSC_SUCCESS); 10578 } 10579