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 PetscBool found = PETSC_FALSE; 89 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 90 91 PetscFunctionBegin; 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 94 PetscCall(ISGetLocalSize(valueIS, &Nct)); 95 PetscCall(ISGetIndices(valueIS, &ctypes)); 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 found = PETSC_TRUE; 114 } 115 if (!Nct || !found) cS = cE = 0; 116 PetscCall(ISDestroy(&valueIS)); 117 // Reset label for fast lookup 118 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 119 if (cStart) *cStart = cS; 120 if (cEnd) *cEnd = cE; 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 125 { 126 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 127 PetscInt *sStart, *sEnd; 128 PetscViewerVTKFieldType *ft; 129 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 130 DMLabel depthLabel, ctLabel; 131 132 PetscFunctionBegin; 133 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 134 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 135 PetscCall(DMGetCoordinateDim(dm, &cdim)); 136 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 137 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 138 if (field >= 0) { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 140 } else { 141 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 142 } 143 144 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 145 PetscCall(DMPlexGetDepth(dm, &depth)); 146 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 147 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 148 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 149 const DMPolytopeType ict = (DMPolytopeType)c; 150 PetscInt dep; 151 152 if (ict == DM_POLYTOPE_FV_GHOST) continue; 153 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 154 if (pStart >= 0) { 155 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 156 if (dep != depth - cellHeight) continue; 157 } 158 if (field >= 0) { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 160 } else { 161 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 162 } 163 } 164 165 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 166 *types = 0; 167 168 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 169 if (globalvcdof[c]) ++(*types); 170 } 171 172 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 173 t = 0; 174 if (globalvcdof[DM_NUM_POLYTOPES]) { 175 sStart[t] = vStart; 176 sEnd[t] = vEnd; 177 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 178 ++t; 179 } 180 181 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 182 if (globalvcdof[c]) { 183 const DMPolytopeType ict = (DMPolytopeType)c; 184 185 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 186 sStart[t] = cStart; 187 sEnd[t] = cEnd; 188 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 189 ++t; 190 } 191 } 192 193 if (!*types) { 194 if (field >= 0) { 195 const char *fieldname; 196 197 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 199 } else { 200 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 201 } 202 } 203 204 *ssStart = sStart; 205 *ssEnd = sEnd; 206 *sft = ft; 207 PetscFunctionReturn(PETSC_SUCCESS); 208 } 209 210 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 211 { 212 PetscFunctionBegin; 213 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 214 PetscFunctionReturn(PETSC_SUCCESS); 215 } 216 217 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 218 { 219 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 220 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 221 222 PetscFunctionBegin; 223 *ft = PETSC_VTK_INVALID; 224 PetscCall(DMGetCoordinateDim(dm, &cdim)); 225 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 226 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 227 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 228 if (field >= 0) { 229 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 230 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 231 } else { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 234 } 235 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 236 if (globalvcdof[0]) { 237 *sStart = vStart; 238 *sEnd = vEnd; 239 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 240 else *ft = PETSC_VTK_POINT_FIELD; 241 } else if (globalvcdof[1]) { 242 *sStart = cStart; 243 *sEnd = cEnd; 244 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 245 else *ft = PETSC_VTK_CELL_FIELD; 246 } else { 247 if (field >= 0) { 248 const char *fieldname; 249 250 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 252 } else { 253 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 254 } 255 } 256 PetscFunctionReturn(PETSC_SUCCESS); 257 } 258 259 /*@ 260 DMPlexVecView1D - Plot many 1D solutions on the same line graph 261 262 Collective 263 264 Input Parameters: 265 + dm - The `DMPLEX` object 266 . n - The number of vectors 267 . u - The array of local vectors 268 - viewer - The `PetscViewer` 269 270 Level: advanced 271 272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 273 @*/ 274 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 275 { 276 PetscDS ds; 277 PetscDraw draw = NULL; 278 PetscDrawLG lg; 279 Vec coordinates; 280 const PetscScalar *coords, **sol; 281 PetscReal *vals; 282 PetscInt *Nc; 283 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 284 char **names; 285 286 PetscFunctionBegin; 287 PetscCall(DMGetDS(dm, &ds)); 288 PetscCall(PetscDSGetNumFields(ds, &Nf)); 289 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 290 PetscCall(PetscDSGetComponents(ds, &Nc)); 291 292 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 293 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 294 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 295 296 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 297 for (i = 0, l = 0; i < n; ++i) { 298 const char *vname; 299 300 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 301 for (f = 0; f < Nf; ++f) { 302 PetscObject disc; 303 const char *fname; 304 char tmpname[PETSC_MAX_PATH_LEN]; 305 306 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 307 /* TODO Create names for components */ 308 for (c = 0; c < Nc[f]; ++c, ++l) { 309 PetscCall(PetscObjectGetName(disc, &fname)); 310 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 312 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 313 PetscCall(PetscStrallocpy(tmpname, &names[l])); 314 } 315 } 316 } 317 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 318 /* Just add P_1 support for now */ 319 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 320 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 321 PetscCall(VecGetArrayRead(coordinates, &coords)); 322 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 323 for (v = vStart; v < vEnd; ++v) { 324 PetscScalar *x, *svals; 325 326 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 327 for (i = 0; i < n; ++i) { 328 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 329 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 330 } 331 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 332 } 333 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 334 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 335 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 336 PetscCall(PetscFree3(sol, names, vals)); 337 338 PetscCall(PetscDrawLGDraw(lg)); 339 PetscCall(PetscDrawLGDestroy(&lg)); 340 PetscFunctionReturn(PETSC_SUCCESS); 341 } 342 343 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 344 { 345 DM dm; 346 347 PetscFunctionBegin; 348 PetscCall(VecGetDM(u, &dm)); 349 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 350 PetscFunctionReturn(PETSC_SUCCESS); 351 } 352 353 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 354 { 355 DM dm; 356 PetscSection s; 357 PetscDraw draw, popup; 358 DM cdm; 359 PetscSection coordSection; 360 Vec coordinates; 361 const PetscScalar *array; 362 PetscReal lbound[3], ubound[3]; 363 PetscReal vbound[2], time; 364 PetscBool flg; 365 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 366 const char *name; 367 char title[PETSC_MAX_PATH_LEN]; 368 369 PetscFunctionBegin; 370 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 371 PetscCall(VecGetDM(v, &dm)); 372 PetscCall(DMGetCoordinateDim(dm, &dim)); 373 PetscCall(DMGetLocalSection(dm, &s)); 374 PetscCall(PetscSectionGetNumFields(s, &Nf)); 375 PetscCall(DMGetCoarsenLevel(dm, &level)); 376 PetscCall(DMGetCoordinateDM(dm, &cdm)); 377 PetscCall(DMGetLocalSection(cdm, &coordSection)); 378 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 379 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 380 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 381 382 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 383 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 384 385 PetscCall(VecGetLocalSize(coordinates, &N)); 386 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 387 PetscCall(PetscDrawClear(draw)); 388 389 /* Could implement something like DMDASelectFields() */ 390 for (f = 0; f < Nf; ++f) { 391 DM fdm = dm; 392 Vec fv = v; 393 IS fis; 394 char prefix[PETSC_MAX_PATH_LEN]; 395 const char *fname; 396 397 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 398 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 399 400 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 401 else prefix[0] = '\0'; 402 if (Nf > 1) { 403 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 404 PetscCall(VecGetSubVector(v, fis, &fv)); 405 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 406 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 407 } 408 for (comp = 0; comp < Nc; ++comp, ++w) { 409 PetscInt nmax = 2; 410 411 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 412 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 413 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 414 PetscCall(PetscDrawSetTitle(draw, title)); 415 416 /* TODO Get max and min only for this component */ 417 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 418 if (!flg) { 419 PetscCall(VecMin(fv, NULL, &vbound[0])); 420 PetscCall(VecMax(fv, NULL, &vbound[1])); 421 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 422 } 423 424 PetscCall(PetscDrawGetPopup(draw, &popup)); 425 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 426 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 427 PetscCall(VecGetArrayRead(fv, &array)); 428 for (c = cStart; c < cEnd; ++c) { 429 PetscScalar *coords = NULL, *a = NULL; 430 const PetscScalar *coords_arr; 431 PetscBool isDG; 432 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 433 434 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 435 if (a) { 436 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 437 color[1] = color[2] = color[3] = color[0]; 438 } else { 439 PetscScalar *vals = NULL; 440 PetscInt numVals, va; 441 442 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 443 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); 444 switch (numVals / Nc) { 445 case 3: /* P1 Triangle */ 446 case 4: /* P1 Quadrangle */ 447 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 448 break; 449 case 6: /* P2 Triangle */ 450 case 8: /* P2 Quadrangle */ 451 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 452 break; 453 default: 454 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 455 } 456 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 457 } 458 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 459 switch (numCoords) { 460 case 6: 461 case 12: /* Localized triangle */ 462 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])); 463 break; 464 case 8: 465 case 16: /* Localized quadrilateral */ 466 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])); 467 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])); 468 break; 469 default: 470 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 471 } 472 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 473 } 474 PetscCall(VecRestoreArrayRead(fv, &array)); 475 PetscCall(PetscDrawFlush(draw)); 476 PetscCall(PetscDrawPause(draw)); 477 PetscCall(PetscDrawSave(draw)); 478 } 479 if (Nf > 1) { 480 PetscCall(VecRestoreSubVector(v, fis, &fv)); 481 PetscCall(ISDestroy(&fis)); 482 PetscCall(DMDestroy(&fdm)); 483 } 484 } 485 PetscFunctionReturn(PETSC_SUCCESS); 486 } 487 488 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 489 { 490 DM dm; 491 PetscDraw draw; 492 PetscInt dim; 493 PetscBool isnull; 494 495 PetscFunctionBegin; 496 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 497 PetscCall(PetscDrawIsNull(draw, &isnull)); 498 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 499 500 PetscCall(VecGetDM(v, &dm)); 501 PetscCall(DMGetCoordinateDim(dm, &dim)); 502 switch (dim) { 503 case 1: 504 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 505 break; 506 case 2: 507 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 508 break; 509 default: 510 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 511 } 512 PetscFunctionReturn(PETSC_SUCCESS); 513 } 514 515 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 516 { 517 DM dm; 518 Vec locv; 519 const char *name; 520 PetscSection section; 521 PetscInt pStart, pEnd; 522 PetscInt numFields; 523 PetscViewerVTKFieldType ft; 524 525 PetscFunctionBegin; 526 PetscCall(VecGetDM(v, &dm)); 527 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 528 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 529 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 530 PetscCall(VecCopy(v, locv)); 531 PetscCall(DMGetLocalSection(dm, §ion)); 532 PetscCall(PetscSectionGetNumFields(section, &numFields)); 533 if (!numFields) { 534 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 535 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 536 } else { 537 PetscInt f; 538 539 for (f = 0; f < numFields; f++) { 540 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 541 if (ft == PETSC_VTK_INVALID) continue; 542 PetscCall(PetscObjectReference((PetscObject)locv)); 543 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 544 } 545 PetscCall(VecDestroy(&locv)); 546 } 547 PetscFunctionReturn(PETSC_SUCCESS); 548 } 549 550 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 551 { 552 DM dm; 553 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 554 555 PetscFunctionBegin; 556 PetscCall(VecGetDM(v, &dm)); 557 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 562 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 563 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 564 PetscInt i, numFields; 565 PetscObject fe; 566 PetscBool fem = PETSC_FALSE; 567 Vec locv = v; 568 const char *name; 569 PetscInt step; 570 PetscReal time; 571 572 PetscCall(DMGetNumFields(dm, &numFields)); 573 for (i = 0; i < numFields; i++) { 574 PetscCall(DMGetField(dm, i, NULL, &fe)); 575 if (fe->classid == PETSCFE_CLASSID) { 576 fem = PETSC_TRUE; 577 break; 578 } 579 } 580 if (fem) { 581 PetscObject isZero; 582 583 PetscCall(DMGetLocalVector(dm, &locv)); 584 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 585 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 586 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 587 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 588 PetscCall(VecCopy(v, locv)); 589 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 590 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 591 } 592 if (isvtk) { 593 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 594 } else if (ishdf5) { 595 #if defined(PETSC_HAVE_HDF5) 596 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 597 #else 598 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 599 #endif 600 } else if (isdraw) { 601 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 602 } else if (isglvis) { 603 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 604 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 605 PetscCall(VecView_GLVis(locv, viewer)); 606 } else if (iscgns) { 607 #if defined(PETSC_HAVE_CGNS) 608 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 609 #else 610 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 611 #endif 612 } 613 if (fem) { 614 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 615 PetscCall(DMRestoreLocalVector(dm, &locv)); 616 } 617 } else { 618 PetscBool isseq; 619 620 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 621 if (isseq) PetscCall(VecView_Seq(v, viewer)); 622 else PetscCall(VecView_MPI(v, viewer)); 623 } 624 PetscFunctionReturn(PETSC_SUCCESS); 625 } 626 627 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 641 if (isvtk || isdraw || isglvis || iscgns) { 642 Vec locv; 643 PetscObject isZero; 644 const char *name; 645 646 PetscCall(DMGetLocalVector(dm, &locv)); 647 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 648 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 649 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 650 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 651 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 652 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 653 PetscCall(VecView_Plex_Local(locv, viewer)); 654 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 655 PetscCall(DMRestoreLocalVector(dm, &locv)); 656 } else if (ishdf5) { 657 #if defined(PETSC_HAVE_HDF5) 658 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 659 #else 660 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 661 #endif 662 } else if (isexodusii) { 663 #if defined(PETSC_HAVE_EXODUSII) 664 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 665 #else 666 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 667 #endif 668 } else { 669 PetscBool isseq; 670 671 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 672 if (isseq) PetscCall(VecView_Seq(v, viewer)); 673 else PetscCall(VecView_MPI(v, viewer)); 674 } 675 PetscFunctionReturn(PETSC_SUCCESS); 676 } 677 678 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 679 { 680 DM dm; 681 MPI_Comm comm; 682 PetscViewerFormat format; 683 Vec v; 684 PetscBool isvtk, ishdf5; 685 686 PetscFunctionBegin; 687 PetscCall(VecGetDM(originalv, &dm)); 688 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 689 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 690 PetscCall(PetscViewerGetFormat(viewer, &format)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 692 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 693 if (format == PETSC_VIEWER_NATIVE) { 694 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 695 /* this need a better fix */ 696 if (dm->useNatural) { 697 if (dm->sfNatural) { 698 const char *vecname; 699 PetscInt n, nroots; 700 701 PetscCall(VecGetLocalSize(originalv, &n)); 702 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 703 if (n == nroots) { 704 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 705 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 706 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 707 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 708 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 709 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 710 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 711 } else v = originalv; 712 } else v = originalv; 713 714 if (ishdf5) { 715 #if defined(PETSC_HAVE_HDF5) 716 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 717 #else 718 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 719 #endif 720 } else if (isvtk) { 721 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 722 } else { 723 PetscBool isseq; 724 725 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 726 if (isseq) PetscCall(VecView_Seq(v, viewer)); 727 else PetscCall(VecView_MPI(v, viewer)); 728 } 729 if (v != originalv) PetscCall(VecDestroy(&v)); 730 PetscFunctionReturn(PETSC_SUCCESS); 731 } 732 733 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 734 { 735 DM dm; 736 PetscBool ishdf5; 737 738 PetscFunctionBegin; 739 PetscCall(VecGetDM(v, &dm)); 740 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 741 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 742 if (ishdf5) { 743 DM dmBC; 744 Vec gv; 745 const char *name; 746 747 PetscCall(DMGetOutputDM(dm, &dmBC)); 748 PetscCall(DMGetGlobalVector(dmBC, &gv)); 749 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 750 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 751 PetscCall(VecLoad_Default(gv, viewer)); 752 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 753 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 754 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 755 } else PetscCall(VecLoad_Default(v, viewer)); 756 PetscFunctionReturn(PETSC_SUCCESS); 757 } 758 759 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 760 { 761 DM dm; 762 PetscBool ishdf5, isexodusii; 763 764 PetscFunctionBegin; 765 PetscCall(VecGetDM(v, &dm)); 766 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 768 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 769 if (ishdf5) { 770 #if defined(PETSC_HAVE_HDF5) 771 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 772 #else 773 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 774 #endif 775 } else if (isexodusii) { 776 #if defined(PETSC_HAVE_EXODUSII) 777 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 778 #else 779 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 780 #endif 781 } else PetscCall(VecLoad_Default(v, viewer)); 782 PetscFunctionReturn(PETSC_SUCCESS); 783 } 784 785 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 786 { 787 DM dm; 788 PetscViewerFormat format; 789 PetscBool ishdf5; 790 791 PetscFunctionBegin; 792 PetscCall(VecGetDM(originalv, &dm)); 793 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 794 PetscCall(PetscViewerGetFormat(viewer, &format)); 795 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 796 if (format == PETSC_VIEWER_NATIVE) { 797 if (dm->useNatural) { 798 if (dm->sfNatural) { 799 if (ishdf5) { 800 #if defined(PETSC_HAVE_HDF5) 801 Vec v; 802 const char *vecname; 803 804 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 805 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 806 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 807 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 808 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 809 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 810 PetscCall(VecDestroy(&v)); 811 #else 812 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 813 #endif 814 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 815 } 816 } else PetscCall(VecLoad_Default(originalv, viewer)); 817 } 818 PetscFunctionReturn(PETSC_SUCCESS); 819 } 820 821 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 822 { 823 PetscSection coordSection; 824 Vec coordinates; 825 DMLabel depthLabel, celltypeLabel; 826 const char *name[4]; 827 const PetscScalar *a; 828 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 829 830 PetscFunctionBegin; 831 PetscCall(DMGetDimension(dm, &dim)); 832 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 833 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 834 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 835 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 836 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 837 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 838 PetscCall(VecGetArrayRead(coordinates, &a)); 839 name[0] = "vertex"; 840 name[1] = "edge"; 841 name[dim - 1] = "face"; 842 name[dim] = "cell"; 843 for (c = cStart; c < cEnd; ++c) { 844 PetscInt *closure = NULL; 845 PetscInt closureSize, cl, ct; 846 847 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 848 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 849 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 850 PetscCall(PetscViewerASCIIPushTab(viewer)); 851 for (cl = 0; cl < closureSize * 2; cl += 2) { 852 PetscInt point = closure[cl], depth, dof, off, d, p; 853 854 if ((point < pStart) || (point >= pEnd)) continue; 855 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 856 if (!dof) continue; 857 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 858 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 859 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 860 for (p = 0; p < dof / dim; ++p) { 861 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 862 for (d = 0; d < dim; ++d) { 863 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 864 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 865 } 866 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 867 } 868 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 869 } 870 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 871 PetscCall(PetscViewerASCIIPopTab(viewer)); 872 } 873 PetscCall(VecRestoreArrayRead(coordinates, &a)); 874 PetscFunctionReturn(PETSC_SUCCESS); 875 } 876 877 typedef enum { 878 CS_CARTESIAN, 879 CS_POLAR, 880 CS_CYLINDRICAL, 881 CS_SPHERICAL 882 } CoordSystem; 883 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 884 885 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 886 { 887 PetscInt i; 888 889 PetscFunctionBegin; 890 if (dim > 3) { 891 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 892 } else { 893 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 894 895 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 896 switch (cs) { 897 case CS_CARTESIAN: 898 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 899 break; 900 case CS_POLAR: 901 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 902 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 903 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 904 break; 905 case CS_CYLINDRICAL: 906 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 907 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 908 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 909 trcoords[2] = coords[2]; 910 break; 911 case CS_SPHERICAL: 912 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 913 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 914 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 915 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 916 break; 917 } 918 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 919 } 920 PetscFunctionReturn(PETSC_SUCCESS); 921 } 922 923 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 924 { 925 DM_Plex *mesh = (DM_Plex *)dm->data; 926 DM cdm, cdmCell; 927 PetscSection coordSection, coordSectionCell; 928 Vec coordinates, coordinatesCell; 929 PetscViewerFormat format; 930 931 PetscFunctionBegin; 932 PetscCall(PetscViewerGetFormat(viewer, &format)); 933 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 934 const char *name; 935 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 936 PetscInt pStart, pEnd, p, numLabels, l; 937 PetscMPIInt rank, size; 938 939 PetscCall(DMGetCoordinateDM(dm, &cdm)); 940 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 941 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 942 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 943 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 944 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 945 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 946 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 947 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 948 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 949 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 950 PetscCall(DMGetDimension(dm, &dim)); 951 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 952 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 953 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 954 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 955 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 956 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 957 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 958 for (p = pStart; p < pEnd; ++p) { 959 PetscInt dof, off, s; 960 961 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 962 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 963 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 964 } 965 PetscCall(PetscViewerFlush(viewer)); 966 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 967 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 968 for (p = pStart; p < pEnd; ++p) { 969 PetscInt dof, off, c; 970 971 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 972 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 973 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])); 974 } 975 PetscCall(PetscViewerFlush(viewer)); 976 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 977 if (coordSection && coordinates) { 978 CoordSystem cs = CS_CARTESIAN; 979 const PetscScalar *array, *arrayCell = NULL; 980 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 981 PetscMPIInt rank; 982 const char *name; 983 984 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 985 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 986 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 987 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 988 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 989 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 990 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 991 pStart = PetscMin(pvStart, pcStart); 992 pEnd = PetscMax(pvEnd, pcEnd); 993 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 994 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 995 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 996 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 997 998 PetscCall(VecGetArrayRead(coordinates, &array)); 999 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1000 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1001 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1002 for (p = pStart; p < pEnd; ++p) { 1003 PetscInt dof, off; 1004 1005 if (p >= pvStart && p < pvEnd) { 1006 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1007 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1008 if (dof) { 1009 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1010 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1011 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1012 } 1013 } 1014 if (cdmCell && p >= pcStart && p < pcEnd) { 1015 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1016 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1017 if (dof) { 1018 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1019 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1020 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1021 } 1022 } 1023 } 1024 PetscCall(PetscViewerFlush(viewer)); 1025 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1026 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1027 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1028 } 1029 PetscCall(DMGetNumLabels(dm, &numLabels)); 1030 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1031 for (l = 0; l < numLabels; ++l) { 1032 DMLabel label; 1033 PetscBool isdepth; 1034 const char *name; 1035 1036 PetscCall(DMGetLabelName(dm, l, &name)); 1037 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1038 if (isdepth) continue; 1039 PetscCall(DMGetLabel(dm, name, &label)); 1040 PetscCall(DMLabelView(label, viewer)); 1041 } 1042 if (size > 1) { 1043 PetscSF sf; 1044 1045 PetscCall(DMGetPointSF(dm, &sf)); 1046 PetscCall(PetscSFView(sf, viewer)); 1047 } 1048 if (mesh->periodic.face_sfs) 1049 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1050 PetscCall(PetscViewerFlush(viewer)); 1051 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1052 const char *name, *color; 1053 const char *defcolors[3] = {"gray", "orange", "green"}; 1054 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1055 char lname[PETSC_MAX_PATH_LEN]; 1056 PetscReal scale = 2.0; 1057 PetscReal tikzscale = 1.0; 1058 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1059 double tcoords[3]; 1060 PetscScalar *coords; 1061 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; 1062 PetscMPIInt rank, size; 1063 char **names, **colors, **lcolors; 1064 PetscBool flg, lflg; 1065 PetscBT wp = NULL; 1066 PetscInt pEnd, pStart; 1067 1068 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1069 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1070 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1071 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1072 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1073 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1074 PetscCall(DMGetDimension(dm, &dim)); 1075 PetscCall(DMPlexGetDepth(dm, &depth)); 1076 PetscCall(DMGetNumLabels(dm, &numLabels)); 1077 numLabels = PetscMax(numLabels, 10); 1078 numColors = 10; 1079 numLColors = 10; 1080 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1081 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1082 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1083 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1084 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1085 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1086 n = 4; 1087 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1088 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1089 n = 4; 1090 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1091 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1093 if (!useLabels) numLabels = 0; 1094 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1095 if (!useColors) { 1096 numColors = 3; 1097 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1098 } 1099 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1100 if (!useColors) { 1101 numLColors = 4; 1102 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1103 } 1104 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1105 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1106 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1107 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1108 if (depth < dim) plotEdges = PETSC_FALSE; 1109 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1110 1111 /* filter points with labelvalue != labeldefaultvalue */ 1112 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1113 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1114 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1115 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1116 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1117 if (lflg) { 1118 DMLabel lbl; 1119 1120 PetscCall(DMGetLabel(dm, lname, &lbl)); 1121 if (lbl) { 1122 PetscInt val, defval; 1123 1124 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1125 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1126 for (c = pStart; c < pEnd; c++) { 1127 PetscInt *closure = NULL; 1128 PetscInt closureSize; 1129 1130 PetscCall(DMLabelGetValue(lbl, c, &val)); 1131 if (val == defval) continue; 1132 1133 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1134 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1135 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1136 } 1137 } 1138 } 1139 1140 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1141 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1142 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1143 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1144 \\documentclass[tikz]{standalone}\n\n\ 1145 \\usepackage{pgflibraryshapes}\n\ 1146 \\usetikzlibrary{backgrounds}\n\ 1147 \\usetikzlibrary{arrows}\n\ 1148 \\begin{document}\n")); 1149 if (size > 1) { 1150 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1151 for (p = 0; p < size; ++p) { 1152 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1153 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1154 } 1155 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1156 } 1157 if (drawHasse) { 1158 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1159 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1171 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1172 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1173 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1174 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1175 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1176 } 1177 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1178 1179 /* Plot vertices */ 1180 PetscCall(VecGetArray(coordinates, &coords)); 1181 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1182 for (v = vStart; v < vEnd; ++v) { 1183 PetscInt off, dof, d; 1184 PetscBool isLabeled = PETSC_FALSE; 1185 1186 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1187 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1188 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1189 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1190 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1191 for (d = 0; d < dof; ++d) { 1192 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1193 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1194 } 1195 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1196 if (dim == 3) { 1197 PetscReal tmp = tcoords[1]; 1198 tcoords[1] = tcoords[2]; 1199 tcoords[2] = -tmp; 1200 } 1201 for (d = 0; d < dof; ++d) { 1202 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1203 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1204 } 1205 if (drawHasse) color = colors[0 % numColors]; 1206 else color = colors[rank % numColors]; 1207 for (l = 0; l < numLabels; ++l) { 1208 PetscInt val; 1209 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1210 if (val >= 0) { 1211 color = lcolors[l % numLColors]; 1212 isLabeled = PETSC_TRUE; 1213 break; 1214 } 1215 } 1216 if (drawNumbers[0]) { 1217 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1218 } else if (drawColors[0]) { 1219 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1220 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1221 } 1222 PetscCall(VecRestoreArray(coordinates, &coords)); 1223 PetscCall(PetscViewerFlush(viewer)); 1224 /* Plot edges */ 1225 if (plotEdges) { 1226 PetscCall(VecGetArray(coordinates, &coords)); 1227 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1228 for (e = eStart; e < eEnd; ++e) { 1229 const PetscInt *cone; 1230 PetscInt coneSize, offA, offB, dof, d; 1231 1232 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1233 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1234 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1235 PetscCall(DMPlexGetCone(dm, e, &cone)); 1236 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1237 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1238 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1239 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1240 for (d = 0; d < dof; ++d) { 1241 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1242 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1243 } 1244 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1245 if (dim == 3) { 1246 PetscReal tmp = tcoords[1]; 1247 tcoords[1] = tcoords[2]; 1248 tcoords[2] = -tmp; 1249 } 1250 for (d = 0; d < dof; ++d) { 1251 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1252 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1253 } 1254 if (drawHasse) color = colors[1 % numColors]; 1255 else color = colors[rank % numColors]; 1256 for (l = 0; l < numLabels; ++l) { 1257 PetscInt val; 1258 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1259 if (val >= 0) { 1260 color = lcolors[l % numLColors]; 1261 break; 1262 } 1263 } 1264 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1265 } 1266 PetscCall(VecRestoreArray(coordinates, &coords)); 1267 PetscCall(PetscViewerFlush(viewer)); 1268 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1269 } 1270 /* Plot cells */ 1271 if (dim == 3 || !drawNumbers[1]) { 1272 for (e = eStart; e < eEnd; ++e) { 1273 const PetscInt *cone; 1274 1275 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1276 color = colors[rank % numColors]; 1277 for (l = 0; l < numLabels; ++l) { 1278 PetscInt val; 1279 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1280 if (val >= 0) { 1281 color = lcolors[l % numLColors]; 1282 break; 1283 } 1284 } 1285 PetscCall(DMPlexGetCone(dm, e, &cone)); 1286 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1287 } 1288 } else { 1289 DMPolytopeType ct; 1290 1291 /* Drawing a 2D polygon */ 1292 for (c = cStart; c < cEnd; ++c) { 1293 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1294 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1295 if (DMPolytopeTypeIsHybrid(ct)) { 1296 const PetscInt *cone; 1297 PetscInt coneSize, e; 1298 1299 PetscCall(DMPlexGetCone(dm, c, &cone)); 1300 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1301 for (e = 0; e < coneSize; ++e) { 1302 const PetscInt *econe; 1303 1304 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1305 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)); 1306 } 1307 } else { 1308 PetscInt *closure = NULL; 1309 PetscInt closureSize, Nv = 0, v; 1310 1311 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1312 for (p = 0; p < closureSize * 2; p += 2) { 1313 const PetscInt point = closure[p]; 1314 1315 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1316 } 1317 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1318 for (v = 0; v <= Nv; ++v) { 1319 const PetscInt vertex = closure[v % Nv]; 1320 1321 if (v > 0) { 1322 if (plotEdges) { 1323 const PetscInt *edge; 1324 PetscInt endpoints[2], ne; 1325 1326 endpoints[0] = closure[v - 1]; 1327 endpoints[1] = vertex; 1328 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1329 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1330 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1331 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1332 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1333 } 1334 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1335 } 1336 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1337 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1338 } 1339 } 1340 } 1341 for (c = cStart; c < cEnd; ++c) { 1342 double ccoords[3] = {0.0, 0.0, 0.0}; 1343 PetscBool isLabeled = PETSC_FALSE; 1344 PetscScalar *cellCoords = NULL; 1345 const PetscScalar *array; 1346 PetscInt numCoords, cdim, d; 1347 PetscBool isDG; 1348 1349 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1350 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1351 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1352 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1353 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1354 for (p = 0; p < numCoords / cdim; ++p) { 1355 for (d = 0; d < cdim; ++d) { 1356 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1357 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1358 } 1359 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1360 if (cdim == 3) { 1361 PetscReal tmp = tcoords[1]; 1362 tcoords[1] = tcoords[2]; 1363 tcoords[2] = -tmp; 1364 } 1365 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1366 } 1367 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1368 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1369 for (d = 0; d < cdim; ++d) { 1370 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1371 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1372 } 1373 if (drawHasse) color = colors[depth % numColors]; 1374 else color = colors[rank % numColors]; 1375 for (l = 0; l < numLabels; ++l) { 1376 PetscInt val; 1377 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1378 if (val >= 0) { 1379 color = lcolors[l % numLColors]; 1380 isLabeled = PETSC_TRUE; 1381 break; 1382 } 1383 } 1384 if (drawNumbers[dim]) { 1385 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1386 } else if (drawColors[dim]) { 1387 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1388 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1389 } 1390 if (drawHasse) { 1391 int height = 0; 1392 1393 color = colors[depth % numColors]; 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1397 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1398 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1399 1400 if (depth > 2) { 1401 color = colors[1 % numColors]; 1402 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1404 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1405 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1406 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1407 } 1408 1409 color = colors[1 % numColors]; 1410 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1411 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1412 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1413 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1414 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1415 1416 color = colors[0 % numColors]; 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1418 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1419 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1420 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1421 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1422 1423 for (p = pStart; p < pEnd; ++p) { 1424 const PetscInt *cone; 1425 PetscInt coneSize, cp; 1426 1427 PetscCall(DMPlexGetCone(dm, p, &cone)); 1428 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1429 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1430 } 1431 } 1432 PetscCall(PetscViewerFlush(viewer)); 1433 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1434 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1435 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1436 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1437 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1438 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1439 PetscCall(PetscFree3(names, colors, lcolors)); 1440 PetscCall(PetscBTDestroy(&wp)); 1441 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1442 Vec cown, acown; 1443 VecScatter sct; 1444 ISLocalToGlobalMapping g2l; 1445 IS gid, acis; 1446 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1447 MPI_Group ggroup, ngroup; 1448 PetscScalar *array, nid; 1449 const PetscInt *idxs; 1450 PetscInt *idxs2, *start, *adjacency, *work; 1451 PetscInt64 lm[3], gm[3]; 1452 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1453 PetscMPIInt d1, d2, rank; 1454 1455 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1456 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1457 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1458 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1459 #endif 1460 if (ncomm != MPI_COMM_NULL) { 1461 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1462 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1463 d1 = 0; 1464 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1465 nid = d2; 1466 PetscCallMPI(MPI_Group_free(&ggroup)); 1467 PetscCallMPI(MPI_Group_free(&ngroup)); 1468 PetscCallMPI(MPI_Comm_free(&ncomm)); 1469 } else nid = 0.0; 1470 1471 /* Get connectivity */ 1472 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1473 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1474 1475 /* filter overlapped local cells */ 1476 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1477 PetscCall(ISGetIndices(gid, &idxs)); 1478 PetscCall(ISGetLocalSize(gid, &cum)); 1479 PetscCall(PetscMalloc1(cum, &idxs2)); 1480 for (c = cStart, cum = 0; c < cEnd; c++) { 1481 if (idxs[c - cStart] < 0) continue; 1482 idxs2[cum++] = idxs[c - cStart]; 1483 } 1484 PetscCall(ISRestoreIndices(gid, &idxs)); 1485 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1486 PetscCall(ISDestroy(&gid)); 1487 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1488 1489 /* support for node-aware cell locality */ 1490 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1491 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1492 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1493 PetscCall(VecGetArray(cown, &array)); 1494 for (c = 0; c < numVertices; c++) array[c] = nid; 1495 PetscCall(VecRestoreArray(cown, &array)); 1496 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1497 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1498 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1499 PetscCall(ISDestroy(&acis)); 1500 PetscCall(VecScatterDestroy(&sct)); 1501 PetscCall(VecDestroy(&cown)); 1502 1503 /* compute edgeCut */ 1504 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1505 PetscCall(PetscMalloc1(cum, &work)); 1506 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1507 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1508 PetscCall(ISDestroy(&gid)); 1509 PetscCall(VecGetArray(acown, &array)); 1510 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1511 PetscInt totl; 1512 1513 totl = start[c + 1] - start[c]; 1514 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1515 for (i = 0; i < totl; i++) { 1516 if (work[i] < 0) { 1517 ect += 1; 1518 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1519 } 1520 } 1521 } 1522 PetscCall(PetscFree(work)); 1523 PetscCall(VecRestoreArray(acown, &array)); 1524 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1525 lm[1] = -numVertices; 1526 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1527 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1528 lm[0] = ect; /* edgeCut */ 1529 lm[1] = ectn; /* node-aware edgeCut */ 1530 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1531 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1532 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1533 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1534 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1535 #else 1536 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1537 #endif 1538 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1539 PetscCall(PetscFree(start)); 1540 PetscCall(PetscFree(adjacency)); 1541 PetscCall(VecDestroy(&acown)); 1542 } else { 1543 const char *name; 1544 PetscInt *sizes, *hybsizes, *ghostsizes; 1545 PetscInt locDepth, depth, cellHeight, dim, d; 1546 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1547 PetscInt numLabels, l, maxSize = 17; 1548 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1549 MPI_Comm comm; 1550 PetscMPIInt size, rank; 1551 1552 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1553 PetscCallMPI(MPI_Comm_size(comm, &size)); 1554 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1555 PetscCall(DMGetDimension(dm, &dim)); 1556 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1557 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1558 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1559 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1560 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1561 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1562 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1563 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1564 gcNum = gcEnd - gcStart; 1565 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1566 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1567 for (d = 0; d <= depth; d++) { 1568 PetscInt Nc[2] = {0, 0}, ict; 1569 1570 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1571 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1572 ict = ct0; 1573 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1574 ct0 = (DMPolytopeType)ict; 1575 for (p = pStart; p < pEnd; ++p) { 1576 DMPolytopeType ct; 1577 1578 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1579 if (ct == ct0) ++Nc[0]; 1580 else ++Nc[1]; 1581 } 1582 if (size < maxSize) { 1583 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1584 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1585 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1586 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1587 for (p = 0; p < size; ++p) { 1588 if (rank == 0) { 1589 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1590 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1591 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1592 } 1593 } 1594 } else { 1595 PetscInt locMinMax[2]; 1596 1597 locMinMax[0] = Nc[0] + Nc[1]; 1598 locMinMax[1] = Nc[0] + Nc[1]; 1599 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1600 locMinMax[0] = Nc[1]; 1601 locMinMax[1] = Nc[1]; 1602 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1603 if (d == depth) { 1604 locMinMax[0] = gcNum; 1605 locMinMax[1] = gcNum; 1606 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1607 } 1608 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1609 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1610 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1611 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1612 } 1613 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1614 } 1615 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1616 { 1617 const PetscReal *maxCell; 1618 const PetscReal *L; 1619 PetscBool localized; 1620 1621 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1622 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1623 if (L || localized) { 1624 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1625 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1626 if (L) { 1627 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1628 for (d = 0; d < dim; ++d) { 1629 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1630 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1631 } 1632 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1633 } 1634 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1635 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1636 } 1637 } 1638 PetscCall(DMGetNumLabels(dm, &numLabels)); 1639 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1640 for (l = 0; l < numLabels; ++l) { 1641 DMLabel label; 1642 const char *name; 1643 IS valueIS; 1644 const PetscInt *values; 1645 PetscInt numValues, v; 1646 1647 PetscCall(DMGetLabelName(dm, l, &name)); 1648 PetscCall(DMGetLabel(dm, name, &label)); 1649 PetscCall(DMLabelGetNumValues(label, &numValues)); 1650 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1651 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1652 PetscCall(ISGetIndices(valueIS, &values)); 1653 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1654 for (v = 0; v < numValues; ++v) { 1655 PetscInt size; 1656 1657 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1658 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1659 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1660 } 1661 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1662 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1663 PetscCall(ISRestoreIndices(valueIS, &values)); 1664 PetscCall(ISDestroy(&valueIS)); 1665 } 1666 { 1667 char **labelNames; 1668 PetscInt Nl = numLabels; 1669 PetscBool flg; 1670 1671 PetscCall(PetscMalloc1(Nl, &labelNames)); 1672 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1673 for (l = 0; l < Nl; ++l) { 1674 DMLabel label; 1675 1676 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1677 if (flg) { 1678 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1679 PetscCall(DMLabelView(label, viewer)); 1680 } 1681 PetscCall(PetscFree(labelNames[l])); 1682 } 1683 PetscCall(PetscFree(labelNames)); 1684 } 1685 /* If no fields are specified, people do not want to see adjacency */ 1686 if (dm->Nf) { 1687 PetscInt f; 1688 1689 for (f = 0; f < dm->Nf; ++f) { 1690 const char *name; 1691 1692 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1693 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1694 PetscCall(PetscViewerASCIIPushTab(viewer)); 1695 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1696 if (dm->fields[f].adjacency[0]) { 1697 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1698 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1699 } else { 1700 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1701 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1702 } 1703 PetscCall(PetscViewerASCIIPopTab(viewer)); 1704 } 1705 } 1706 PetscCall(DMGetCoarseDM(dm, &cdm)); 1707 if (cdm) { 1708 PetscCall(PetscViewerASCIIPushTab(viewer)); 1709 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1710 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1711 PetscCall(PetscViewerASCIIPopTab(viewer)); 1712 } 1713 } 1714 PetscFunctionReturn(PETSC_SUCCESS); 1715 } 1716 1717 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1718 { 1719 DMPolytopeType ct; 1720 PetscMPIInt rank; 1721 PetscInt cdim; 1722 1723 PetscFunctionBegin; 1724 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1725 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1726 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1727 switch (ct) { 1728 case DM_POLYTOPE_SEGMENT: 1729 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1730 switch (cdim) { 1731 case 1: { 1732 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1733 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1734 1735 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1738 } break; 1739 case 2: { 1740 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1741 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1742 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1743 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1745 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)); 1746 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)); 1747 } break; 1748 default: 1749 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1750 } 1751 break; 1752 case DM_POLYTOPE_TRIANGLE: 1753 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)); 1754 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1755 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1756 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1757 break; 1758 case DM_POLYTOPE_QUADRILATERAL: 1759 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)); 1760 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)); 1761 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1762 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1763 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1764 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1765 break; 1766 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1767 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)); 1768 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)); 1769 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1770 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1771 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1772 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1773 break; 1774 case DM_POLYTOPE_FV_GHOST: 1775 break; 1776 default: 1777 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1778 } 1779 PetscFunctionReturn(PETSC_SUCCESS); 1780 } 1781 1782 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1783 { 1784 PetscReal centroid[2] = {0., 0.}; 1785 PetscMPIInt rank; 1786 PetscInt fillColor; 1787 1788 PetscFunctionBegin; 1789 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1790 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1791 for (PetscInt v = 0; v < Nv; ++v) { 1792 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1793 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1794 } 1795 for (PetscInt e = 0; e < Nv; ++e) { 1796 refCoords[0] = refVertices[e * 2 + 0]; 1797 refCoords[1] = refVertices[e * 2 + 1]; 1798 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1799 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1800 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1801 } 1802 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1803 for (PetscInt d = 0; d < edgeDiv; ++d) { 1804 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)); 1805 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1806 } 1807 } 1808 PetscFunctionReturn(PETSC_SUCCESS); 1809 } 1810 1811 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1812 { 1813 DMPolytopeType ct; 1814 1815 PetscFunctionBegin; 1816 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1817 switch (ct) { 1818 case DM_POLYTOPE_TRIANGLE: { 1819 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1820 1821 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1822 } break; 1823 case DM_POLYTOPE_QUADRILATERAL: { 1824 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1825 1826 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1827 } break; 1828 default: 1829 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1830 } 1831 PetscFunctionReturn(PETSC_SUCCESS); 1832 } 1833 1834 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1835 { 1836 PetscDraw draw; 1837 DM cdm; 1838 PetscSection coordSection; 1839 Vec coordinates; 1840 PetscReal xyl[3], xyr[3]; 1841 PetscReal *refCoords, *edgeCoords; 1842 PetscBool isnull, drawAffine; 1843 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1844 1845 PetscFunctionBegin; 1846 PetscCall(DMGetCoordinateDim(dm, &dim)); 1847 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1848 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1849 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1850 edgeDiv = cDegree + 1; 1851 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1852 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1853 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1854 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1855 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1856 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1857 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1858 1859 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1860 PetscCall(PetscDrawIsNull(draw, &isnull)); 1861 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1862 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1863 1864 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1865 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1866 PetscCall(PetscDrawClear(draw)); 1867 1868 for (c = cStart; c < cEnd; ++c) { 1869 PetscScalar *coords = NULL; 1870 const PetscScalar *coords_arr; 1871 PetscInt numCoords; 1872 PetscBool isDG; 1873 1874 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1875 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1876 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1877 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1878 } 1879 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1880 PetscCall(PetscDrawFlush(draw)); 1881 PetscCall(PetscDrawPause(draw)); 1882 PetscCall(PetscDrawSave(draw)); 1883 PetscFunctionReturn(PETSC_SUCCESS); 1884 } 1885 1886 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1887 { 1888 DM odm = dm, rdm = dm, cdm; 1889 PetscFE fe; 1890 PetscSpace sp; 1891 PetscClassId id; 1892 PetscInt degree; 1893 PetscBool hoView = PETSC_TRUE; 1894 1895 PetscFunctionBegin; 1896 PetscObjectOptionsBegin((PetscObject)dm); 1897 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1898 PetscOptionsEnd(); 1899 PetscCall(PetscObjectReference((PetscObject)dm)); 1900 *hdm = dm; 1901 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1902 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1903 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1904 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1905 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1906 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1907 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1908 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1909 DM cdm, rcdm; 1910 Mat In; 1911 Vec cl, rcl; 1912 1913 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1914 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1915 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1916 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1917 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1918 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1919 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1920 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1921 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1922 PetscCall(MatMult(In, cl, rcl)); 1923 PetscCall(MatDestroy(&In)); 1924 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1925 PetscCall(DMDestroy(&odm)); 1926 odm = rdm; 1927 } 1928 *hdm = rdm; 1929 PetscFunctionReturn(PETSC_SUCCESS); 1930 } 1931 1932 #if defined(PETSC_HAVE_EXODUSII) 1933 #include <exodusII.h> 1934 #include <petscviewerexodusii.h> 1935 #endif 1936 1937 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1938 { 1939 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1940 char name[PETSC_MAX_PATH_LEN]; 1941 1942 PetscFunctionBegin; 1943 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1944 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1945 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1946 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1947 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1948 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1949 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1950 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1951 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1952 if (iascii) { 1953 PetscViewerFormat format; 1954 PetscCall(PetscViewerGetFormat(viewer, &format)); 1955 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1956 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1957 } else if (ishdf5) { 1958 #if defined(PETSC_HAVE_HDF5) 1959 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1960 #else 1961 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1962 #endif 1963 } else if (isvtk) { 1964 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1965 } else if (isdraw) { 1966 DM hdm; 1967 1968 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1969 PetscCall(DMPlexView_Draw(hdm, viewer)); 1970 PetscCall(DMDestroy(&hdm)); 1971 } else if (isglvis) { 1972 PetscCall(DMPlexView_GLVis(dm, viewer)); 1973 #if defined(PETSC_HAVE_EXODUSII) 1974 } else if (isexodus) { 1975 /* 1976 exodusII requires that all sets be part of exactly one cell set. 1977 If the dm does not have a "Cell Sets" label defined, we create one 1978 with ID 1, containing all cells. 1979 Note that if the Cell Sets label is defined but does not cover all cells, 1980 we may still have a problem. This should probably be checked here or in the viewer; 1981 */ 1982 PetscInt numCS; 1983 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1984 if (!numCS) { 1985 PetscInt cStart, cEnd, c; 1986 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1987 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1988 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1989 } 1990 PetscCall(DMView_PlexExodusII(dm, viewer)); 1991 #endif 1992 #if defined(PETSC_HAVE_CGNS) 1993 } else if (iscgns) { 1994 PetscCall(DMView_PlexCGNS(dm, viewer)); 1995 #endif 1996 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1997 /* Optionally view the partition */ 1998 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1999 if (flg) { 2000 Vec ranks; 2001 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2002 PetscCall(VecView(ranks, viewer)); 2003 PetscCall(VecDestroy(&ranks)); 2004 } 2005 /* Optionally view a label */ 2006 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2007 if (flg) { 2008 DMLabel label; 2009 Vec val; 2010 2011 PetscCall(DMGetLabel(dm, name, &label)); 2012 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2013 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2014 PetscCall(VecView(val, viewer)); 2015 PetscCall(VecDestroy(&val)); 2016 } 2017 PetscFunctionReturn(PETSC_SUCCESS); 2018 } 2019 2020 /*@ 2021 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2022 2023 Collective 2024 2025 Input Parameters: 2026 + dm - The `DM` whose topology is to be saved 2027 - viewer - The `PetscViewer` to save it in 2028 2029 Level: advanced 2030 2031 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2032 @*/ 2033 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2034 { 2035 PetscBool ishdf5; 2036 2037 PetscFunctionBegin; 2038 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2039 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2040 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2041 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2042 if (ishdf5) { 2043 #if defined(PETSC_HAVE_HDF5) 2044 PetscViewerFormat format; 2045 PetscCall(PetscViewerGetFormat(viewer, &format)); 2046 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2047 IS globalPointNumbering; 2048 2049 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2050 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2051 PetscCall(ISDestroy(&globalPointNumbering)); 2052 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2053 #else 2054 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2055 #endif 2056 } 2057 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2058 PetscFunctionReturn(PETSC_SUCCESS); 2059 } 2060 2061 /*@ 2062 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2063 2064 Collective 2065 2066 Input Parameters: 2067 + dm - The `DM` whose coordinates are to be saved 2068 - viewer - The `PetscViewer` for saving 2069 2070 Level: advanced 2071 2072 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2073 @*/ 2074 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2075 { 2076 PetscBool ishdf5; 2077 2078 PetscFunctionBegin; 2079 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2080 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2081 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2082 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2083 if (ishdf5) { 2084 #if defined(PETSC_HAVE_HDF5) 2085 PetscViewerFormat format; 2086 PetscCall(PetscViewerGetFormat(viewer, &format)); 2087 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2088 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2089 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2090 #else 2091 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2092 #endif 2093 } 2094 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2095 PetscFunctionReturn(PETSC_SUCCESS); 2096 } 2097 2098 /*@ 2099 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2100 2101 Collective 2102 2103 Input Parameters: 2104 + dm - The `DM` whose labels are to be saved 2105 - viewer - The `PetscViewer` for saving 2106 2107 Level: advanced 2108 2109 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2110 @*/ 2111 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2112 { 2113 PetscBool ishdf5; 2114 2115 PetscFunctionBegin; 2116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2117 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2118 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2119 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2120 if (ishdf5) { 2121 #if defined(PETSC_HAVE_HDF5) 2122 IS globalPointNumbering; 2123 PetscViewerFormat format; 2124 2125 PetscCall(PetscViewerGetFormat(viewer, &format)); 2126 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2127 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2128 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2129 PetscCall(ISDestroy(&globalPointNumbering)); 2130 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2131 #else 2132 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2133 #endif 2134 } 2135 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2136 PetscFunctionReturn(PETSC_SUCCESS); 2137 } 2138 2139 /*@ 2140 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2141 2142 Collective 2143 2144 Input Parameters: 2145 + dm - The `DM` that contains the topology on which the section to be saved is defined 2146 . viewer - The `PetscViewer` for saving 2147 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2148 2149 Level: advanced 2150 2151 Notes: 2152 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. 2153 2154 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. 2155 2156 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2157 @*/ 2158 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2159 { 2160 PetscBool ishdf5; 2161 2162 PetscFunctionBegin; 2163 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2164 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2165 if (!sectiondm) sectiondm = dm; 2166 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2167 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2168 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2169 if (ishdf5) { 2170 #if defined(PETSC_HAVE_HDF5) 2171 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2172 #else 2173 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2174 #endif 2175 } 2176 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2177 PetscFunctionReturn(PETSC_SUCCESS); 2178 } 2179 2180 /*@ 2181 DMPlexGlobalVectorView - Saves a global vector 2182 2183 Collective 2184 2185 Input Parameters: 2186 + dm - The `DM` that represents the topology 2187 . viewer - The `PetscViewer` to save data with 2188 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2189 - vec - The global vector to be saved 2190 2191 Level: advanced 2192 2193 Notes: 2194 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. 2195 2196 Calling sequence: 2197 .vb 2198 DMCreate(PETSC_COMM_WORLD, &dm); 2199 DMSetType(dm, DMPLEX); 2200 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2201 DMClone(dm, §iondm); 2202 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2203 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2204 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2205 PetscSectionSetChart(section, pStart, pEnd); 2206 PetscSectionSetUp(section); 2207 DMSetLocalSection(sectiondm, section); 2208 PetscSectionDestroy(§ion); 2209 DMGetGlobalVector(sectiondm, &vec); 2210 PetscObjectSetName((PetscObject)vec, "vec_name"); 2211 DMPlexTopologyView(dm, viewer); 2212 DMPlexSectionView(dm, viewer, sectiondm); 2213 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2214 DMRestoreGlobalVector(sectiondm, &vec); 2215 DMDestroy(§iondm); 2216 DMDestroy(&dm); 2217 .ve 2218 2219 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2220 @*/ 2221 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2222 { 2223 PetscBool ishdf5; 2224 2225 PetscFunctionBegin; 2226 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2227 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2228 if (!sectiondm) sectiondm = dm; 2229 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2230 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2231 /* Check consistency */ 2232 { 2233 PetscSection section; 2234 PetscBool includesConstraints; 2235 PetscInt m, m1; 2236 2237 PetscCall(VecGetLocalSize(vec, &m1)); 2238 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2239 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2240 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2241 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2242 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2243 } 2244 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2245 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2246 if (ishdf5) { 2247 #if defined(PETSC_HAVE_HDF5) 2248 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2249 #else 2250 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2251 #endif 2252 } 2253 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2254 PetscFunctionReturn(PETSC_SUCCESS); 2255 } 2256 2257 /*@ 2258 DMPlexLocalVectorView - Saves a local vector 2259 2260 Collective 2261 2262 Input Parameters: 2263 + dm - The `DM` that represents the topology 2264 . viewer - The `PetscViewer` to save data with 2265 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2266 - vec - The local vector to be saved 2267 2268 Level: advanced 2269 2270 Note: 2271 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. 2272 2273 Calling sequence: 2274 .vb 2275 DMCreate(PETSC_COMM_WORLD, &dm); 2276 DMSetType(dm, DMPLEX); 2277 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2278 DMClone(dm, §iondm); 2279 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2280 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2281 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2282 PetscSectionSetChart(section, pStart, pEnd); 2283 PetscSectionSetUp(section); 2284 DMSetLocalSection(sectiondm, section); 2285 DMGetLocalVector(sectiondm, &vec); 2286 PetscObjectSetName((PetscObject)vec, "vec_name"); 2287 DMPlexTopologyView(dm, viewer); 2288 DMPlexSectionView(dm, viewer, sectiondm); 2289 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2290 DMRestoreLocalVector(sectiondm, &vec); 2291 DMDestroy(§iondm); 2292 DMDestroy(&dm); 2293 .ve 2294 2295 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2296 @*/ 2297 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2298 { 2299 PetscBool ishdf5; 2300 2301 PetscFunctionBegin; 2302 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2303 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2304 if (!sectiondm) sectiondm = dm; 2305 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2306 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2307 /* Check consistency */ 2308 { 2309 PetscSection section; 2310 PetscBool includesConstraints; 2311 PetscInt m, m1; 2312 2313 PetscCall(VecGetLocalSize(vec, &m1)); 2314 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2315 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2316 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2317 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2318 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2319 } 2320 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2321 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2322 if (ishdf5) { 2323 #if defined(PETSC_HAVE_HDF5) 2324 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2325 #else 2326 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2327 #endif 2328 } 2329 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2330 PetscFunctionReturn(PETSC_SUCCESS); 2331 } 2332 2333 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2334 { 2335 PetscBool ishdf5; 2336 2337 PetscFunctionBegin; 2338 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2339 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2340 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2341 if (ishdf5) { 2342 #if defined(PETSC_HAVE_HDF5) 2343 PetscViewerFormat format; 2344 PetscCall(PetscViewerGetFormat(viewer, &format)); 2345 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2346 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2347 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2348 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2349 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2350 PetscFunctionReturn(PETSC_SUCCESS); 2351 #else 2352 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2353 #endif 2354 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2355 } 2356 2357 /*@ 2358 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2359 2360 Collective 2361 2362 Input Parameters: 2363 + dm - The `DM` into which the topology is loaded 2364 - viewer - The `PetscViewer` for the saved topology 2365 2366 Output Parameter: 2367 . 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; 2368 `NULL` if unneeded 2369 2370 Level: advanced 2371 2372 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2373 `PetscViewer`, `PetscSF` 2374 @*/ 2375 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2376 { 2377 PetscBool ishdf5; 2378 2379 PetscFunctionBegin; 2380 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2381 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2382 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2383 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2384 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2385 if (ishdf5) { 2386 #if defined(PETSC_HAVE_HDF5) 2387 PetscViewerFormat format; 2388 PetscCall(PetscViewerGetFormat(viewer, &format)); 2389 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2390 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2391 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2392 #else 2393 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2394 #endif 2395 } 2396 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2397 PetscFunctionReturn(PETSC_SUCCESS); 2398 } 2399 2400 /*@ 2401 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2402 2403 Collective 2404 2405 Input Parameters: 2406 + dm - The `DM` into which the coordinates are loaded 2407 . viewer - The `PetscViewer` for the saved coordinates 2408 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2409 2410 Level: advanced 2411 2412 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2413 `PetscSF`, `PetscViewer` 2414 @*/ 2415 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2416 { 2417 PetscBool ishdf5; 2418 2419 PetscFunctionBegin; 2420 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2421 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2422 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2423 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2424 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2425 if (ishdf5) { 2426 #if defined(PETSC_HAVE_HDF5) 2427 PetscViewerFormat format; 2428 PetscCall(PetscViewerGetFormat(viewer, &format)); 2429 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2430 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2431 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2432 #else 2433 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2434 #endif 2435 } 2436 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2437 PetscFunctionReturn(PETSC_SUCCESS); 2438 } 2439 2440 /*@ 2441 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2442 2443 Collective 2444 2445 Input Parameters: 2446 + dm - The `DM` into which the labels are loaded 2447 . viewer - The `PetscViewer` for the saved labels 2448 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2449 2450 Level: advanced 2451 2452 Note: 2453 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2454 2455 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2456 `PetscSF`, `PetscViewer` 2457 @*/ 2458 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2459 { 2460 PetscBool ishdf5; 2461 2462 PetscFunctionBegin; 2463 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2464 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2465 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2466 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2467 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2468 if (ishdf5) { 2469 #if defined(PETSC_HAVE_HDF5) 2470 PetscViewerFormat format; 2471 2472 PetscCall(PetscViewerGetFormat(viewer, &format)); 2473 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2474 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2475 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2476 #else 2477 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2478 #endif 2479 } 2480 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2481 PetscFunctionReturn(PETSC_SUCCESS); 2482 } 2483 2484 /*@ 2485 DMPlexSectionLoad - Loads section into a `DMPLEX` 2486 2487 Collective 2488 2489 Input Parameters: 2490 + dm - The `DM` that represents the topology 2491 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2492 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2493 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2494 2495 Output Parameters: 2496 + 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) 2497 - 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) 2498 2499 Level: advanced 2500 2501 Notes: 2502 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. 2503 2504 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. 2505 2506 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. 2507 2508 Example using 2 processes: 2509 .vb 2510 NX (number of points on dm): 4 2511 sectionA : the on-disk section 2512 vecA : a vector associated with sectionA 2513 sectionB : sectiondm's local section constructed in this function 2514 vecB (local) : a vector associated with sectiondm's local section 2515 vecB (global) : a vector associated with sectiondm's global section 2516 2517 rank 0 rank 1 2518 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2519 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2520 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2521 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2522 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2523 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2524 sectionB->atlasDof : 1 0 1 | 1 3 2525 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2526 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2527 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2528 .ve 2529 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2530 2531 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2532 @*/ 2533 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2534 { 2535 PetscBool ishdf5; 2536 2537 PetscFunctionBegin; 2538 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2539 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2540 if (!sectiondm) sectiondm = dm; 2541 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2542 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2543 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2544 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2545 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2546 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2547 if (ishdf5) { 2548 #if defined(PETSC_HAVE_HDF5) 2549 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2550 #else 2551 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2552 #endif 2553 } 2554 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2555 PetscFunctionReturn(PETSC_SUCCESS); 2556 } 2557 2558 /*@ 2559 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2560 2561 Collective 2562 2563 Input Parameters: 2564 + dm - The `DM` that represents the topology 2565 . viewer - The `PetscViewer` that represents the on-disk vector data 2566 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2567 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2568 - vec - The global vector to set values of 2569 2570 Level: advanced 2571 2572 Notes: 2573 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. 2574 2575 Calling sequence: 2576 .vb 2577 DMCreate(PETSC_COMM_WORLD, &dm); 2578 DMSetType(dm, DMPLEX); 2579 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2580 DMPlexTopologyLoad(dm, viewer, &sfX); 2581 DMClone(dm, §iondm); 2582 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2583 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2584 DMGetGlobalVector(sectiondm, &vec); 2585 PetscObjectSetName((PetscObject)vec, "vec_name"); 2586 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2587 DMRestoreGlobalVector(sectiondm, &vec); 2588 PetscSFDestroy(&gsf); 2589 PetscSFDestroy(&sfX); 2590 DMDestroy(§iondm); 2591 DMDestroy(&dm); 2592 .ve 2593 2594 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2595 `PetscSF`, `PetscViewer` 2596 @*/ 2597 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2598 { 2599 PetscBool ishdf5; 2600 2601 PetscFunctionBegin; 2602 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2603 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2604 if (!sectiondm) sectiondm = dm; 2605 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2606 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2607 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2608 /* Check consistency */ 2609 { 2610 PetscSection section; 2611 PetscBool includesConstraints; 2612 PetscInt m, m1; 2613 2614 PetscCall(VecGetLocalSize(vec, &m1)); 2615 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2616 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2617 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2618 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2619 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2620 } 2621 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2622 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2623 if (ishdf5) { 2624 #if defined(PETSC_HAVE_HDF5) 2625 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2626 #else 2627 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2628 #endif 2629 } 2630 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2631 PetscFunctionReturn(PETSC_SUCCESS); 2632 } 2633 2634 /*@ 2635 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2636 2637 Collective 2638 2639 Input Parameters: 2640 + dm - The `DM` that represents the topology 2641 . viewer - The `PetscViewer` that represents the on-disk vector data 2642 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2643 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2644 - vec - The local vector to set values of 2645 2646 Level: advanced 2647 2648 Notes: 2649 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. 2650 2651 Calling sequence: 2652 .vb 2653 DMCreate(PETSC_COMM_WORLD, &dm); 2654 DMSetType(dm, DMPLEX); 2655 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2656 DMPlexTopologyLoad(dm, viewer, &sfX); 2657 DMClone(dm, §iondm); 2658 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2659 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2660 DMGetLocalVector(sectiondm, &vec); 2661 PetscObjectSetName((PetscObject)vec, "vec_name"); 2662 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2663 DMRestoreLocalVector(sectiondm, &vec); 2664 PetscSFDestroy(&lsf); 2665 PetscSFDestroy(&sfX); 2666 DMDestroy(§iondm); 2667 DMDestroy(&dm); 2668 .ve 2669 2670 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2671 `PetscSF`, `PetscViewer` 2672 @*/ 2673 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2674 { 2675 PetscBool ishdf5; 2676 2677 PetscFunctionBegin; 2678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2679 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2680 if (!sectiondm) sectiondm = dm; 2681 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2682 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2683 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2684 /* Check consistency */ 2685 { 2686 PetscSection section; 2687 PetscBool includesConstraints; 2688 PetscInt m, m1; 2689 2690 PetscCall(VecGetLocalSize(vec, &m1)); 2691 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2692 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2693 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2694 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2695 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2696 } 2697 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2698 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2699 if (ishdf5) { 2700 #if defined(PETSC_HAVE_HDF5) 2701 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2702 #else 2703 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2704 #endif 2705 } 2706 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2707 PetscFunctionReturn(PETSC_SUCCESS); 2708 } 2709 2710 PetscErrorCode DMDestroy_Plex(DM dm) 2711 { 2712 DM_Plex *mesh = (DM_Plex *)dm->data; 2713 2714 PetscFunctionBegin; 2715 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2716 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2717 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2718 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2719 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2720 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2721 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2722 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2723 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2724 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2725 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2726 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2727 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2728 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2729 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2730 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2731 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2732 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2733 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2734 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2735 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2736 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2737 PetscCall(PetscFree(mesh->cones)); 2738 PetscCall(PetscFree(mesh->coneOrientations)); 2739 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2740 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2741 PetscCall(PetscFree(mesh->supports)); 2742 PetscCall(PetscFree(mesh->cellTypes)); 2743 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2744 PetscCall(PetscFree(mesh->tetgenOpts)); 2745 PetscCall(PetscFree(mesh->triangleOpts)); 2746 PetscCall(PetscFree(mesh->transformType)); 2747 PetscCall(PetscFree(mesh->distributionName)); 2748 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2749 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2750 PetscCall(ISDestroy(&mesh->subpointIS)); 2751 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2752 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2753 if (mesh->periodic.face_sfs) { 2754 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2755 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2756 } 2757 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2758 if (mesh->periodic.periodic_points) { 2759 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2760 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2761 } 2762 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2763 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2764 PetscCall(ISDestroy(&mesh->anchorIS)); 2765 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2766 PetscCall(PetscFree(mesh->parents)); 2767 PetscCall(PetscFree(mesh->childIDs)); 2768 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2769 PetscCall(PetscFree(mesh->children)); 2770 PetscCall(DMDestroy(&mesh->referenceTree)); 2771 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2772 PetscCall(PetscFree(mesh->neighbors)); 2773 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2774 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2775 PetscCall(PetscFree(mesh)); 2776 PetscFunctionReturn(PETSC_SUCCESS); 2777 } 2778 2779 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2780 { 2781 PetscSection sectionGlobal, sectionLocal; 2782 PetscInt bs = -1, mbs; 2783 PetscInt localSize, localStart = 0; 2784 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2785 MatType mtype; 2786 ISLocalToGlobalMapping ltog; 2787 2788 PetscFunctionBegin; 2789 PetscCall(MatInitializePackage()); 2790 mtype = dm->mattype; 2791 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2792 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2793 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2794 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2795 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2796 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2797 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2798 PetscCall(MatSetType(*J, mtype)); 2799 PetscCall(MatSetFromOptions(*J)); 2800 PetscCall(MatGetBlockSize(*J, &mbs)); 2801 if (mbs > 1) bs = mbs; 2802 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2803 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2804 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2805 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2806 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2807 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2808 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2809 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2810 if (!isShell) { 2811 // There are three states with pblocks, since block starts can have no dofs: 2812 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2813 // TRUE) Block Start: The first entry in a block has been added 2814 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2815 PetscBT blst; 2816 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2817 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2818 const PetscInt *perm = NULL; 2819 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2820 PetscInt pStart, pEnd, dof, cdof, num_fields; 2821 2822 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2823 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2824 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2825 2826 PetscCall(PetscCalloc1(localSize, &pblocks)); 2827 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2828 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2829 // We need to process in the permuted order to get block sizes right 2830 for (PetscInt point = pStart; point < pEnd; ++point) { 2831 const PetscInt p = perm ? perm[point] : point; 2832 2833 switch (dm->blocking_type) { 2834 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2835 PetscInt bdof, offset; 2836 2837 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2838 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2839 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2840 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2841 if (dof > 0) { 2842 // State change 2843 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2844 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2845 2846 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2847 // Signal block concatenation 2848 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2849 } 2850 dof = dof < 0 ? -(dof + 1) : dof; 2851 bdof = cdof && (dof - cdof) ? 1 : dof; 2852 if (dof) { 2853 if (bs < 0) { 2854 bs = bdof; 2855 } else if (bs != bdof) { 2856 bs = 1; 2857 } 2858 } 2859 } break; 2860 case DM_BLOCKING_FIELD_NODE: { 2861 for (PetscInt field = 0; field < num_fields; field++) { 2862 PetscInt num_comp, bdof, offset; 2863 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2864 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2865 if (dof < 0) continue; 2866 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2867 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2868 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); 2869 PetscInt num_nodes = dof / num_comp; 2870 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2871 // Handle possibly constant block size (unlikely) 2872 bdof = cdof && (dof - cdof) ? 1 : dof; 2873 if (dof) { 2874 if (bs < 0) { 2875 bs = bdof; 2876 } else if (bs != bdof) { 2877 bs = 1; 2878 } 2879 } 2880 } 2881 } break; 2882 } 2883 } 2884 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2885 /* Must have same blocksize on all procs (some might have no points) */ 2886 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2887 bsLocal[1] = bs; 2888 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2889 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2890 else bs = bsMinMax[0]; 2891 bs = PetscMax(1, bs); 2892 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2893 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2894 PetscCall(MatSetBlockSize(*J, bs)); 2895 PetscCall(MatSetUp(*J)); 2896 } else { 2897 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2898 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2899 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2900 } 2901 if (pblocks) { // Consolidate blocks 2902 PetscInt nblocks = 0; 2903 pblocks[0] = PetscAbs(pblocks[0]); 2904 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2905 if (pblocks[i] == 0) continue; 2906 // Negative block size indicates the blocks should be concatenated 2907 if (pblocks[i] < 0) { 2908 pblocks[i] = -pblocks[i]; 2909 pblocks[nblocks - 1] += pblocks[i]; 2910 } else { 2911 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2912 } 2913 for (PetscInt j = 1; j < pblocks[i]; j++) 2914 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 2915 } 2916 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2917 } 2918 PetscCall(PetscFree(pblocks)); 2919 } 2920 PetscCall(MatSetDM(*J, dm)); 2921 PetscFunctionReturn(PETSC_SUCCESS); 2922 } 2923 2924 /*@ 2925 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2926 2927 Not Collective 2928 2929 Input Parameter: 2930 . dm - The `DMPLEX` 2931 2932 Output Parameter: 2933 . subsection - The subdomain section 2934 2935 Level: developer 2936 2937 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2938 @*/ 2939 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2940 { 2941 DM_Plex *mesh = (DM_Plex *)dm->data; 2942 2943 PetscFunctionBegin; 2944 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2945 if (!mesh->subdomainSection) { 2946 PetscSection section; 2947 PetscSF sf; 2948 2949 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2950 PetscCall(DMGetLocalSection(dm, §ion)); 2951 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2952 PetscCall(PetscSFDestroy(&sf)); 2953 } 2954 *subsection = mesh->subdomainSection; 2955 PetscFunctionReturn(PETSC_SUCCESS); 2956 } 2957 2958 /*@ 2959 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2960 2961 Not Collective 2962 2963 Input Parameter: 2964 . dm - The `DMPLEX` 2965 2966 Output Parameters: 2967 + pStart - The first mesh point 2968 - pEnd - The upper bound for mesh points 2969 2970 Level: beginner 2971 2972 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2973 @*/ 2974 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2975 { 2976 DM_Plex *mesh = (DM_Plex *)dm->data; 2977 2978 PetscFunctionBegin; 2979 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2980 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2981 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2982 PetscFunctionReturn(PETSC_SUCCESS); 2983 } 2984 2985 /*@ 2986 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2987 2988 Not Collective 2989 2990 Input Parameters: 2991 + dm - The `DMPLEX` 2992 . pStart - The first mesh point 2993 - pEnd - The upper bound for mesh points 2994 2995 Level: beginner 2996 2997 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2998 @*/ 2999 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3000 { 3001 DM_Plex *mesh = (DM_Plex *)dm->data; 3002 3003 PetscFunctionBegin; 3004 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3005 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3006 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3007 PetscCall(PetscFree(mesh->cellTypes)); 3008 PetscFunctionReturn(PETSC_SUCCESS); 3009 } 3010 3011 /*@ 3012 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3013 3014 Not Collective 3015 3016 Input Parameters: 3017 + dm - The `DMPLEX` 3018 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3019 3020 Output Parameter: 3021 . size - The cone size for point `p` 3022 3023 Level: beginner 3024 3025 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3026 @*/ 3027 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3028 { 3029 DM_Plex *mesh = (DM_Plex *)dm->data; 3030 3031 PetscFunctionBegin; 3032 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3033 PetscAssertPointer(size, 3); 3034 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3035 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3036 PetscFunctionReturn(PETSC_SUCCESS); 3037 } 3038 3039 /*@ 3040 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3041 3042 Not Collective 3043 3044 Input Parameters: 3045 + dm - The `DMPLEX` 3046 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3047 - size - The cone size for point `p` 3048 3049 Level: beginner 3050 3051 Note: 3052 This should be called after `DMPlexSetChart()`. 3053 3054 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3055 @*/ 3056 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3057 { 3058 DM_Plex *mesh = (DM_Plex *)dm->data; 3059 3060 PetscFunctionBegin; 3061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3062 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3063 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3064 PetscFunctionReturn(PETSC_SUCCESS); 3065 } 3066 3067 /*@C 3068 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3069 3070 Not Collective 3071 3072 Input Parameters: 3073 + dm - The `DMPLEX` 3074 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3075 3076 Output Parameter: 3077 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3078 3079 Level: beginner 3080 3081 Fortran Notes: 3082 `cone` must be declared with 3083 .vb 3084 PetscInt, pointer :: cone(:) 3085 .ve 3086 3087 You must also call `DMPlexRestoreCone()` after you finish using the array. 3088 `DMPlexRestoreCone()` is not needed/available in C. 3089 3090 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3091 @*/ 3092 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3093 { 3094 DM_Plex *mesh = (DM_Plex *)dm->data; 3095 PetscInt off; 3096 3097 PetscFunctionBegin; 3098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3099 PetscAssertPointer(cone, 3); 3100 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3101 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3102 PetscFunctionReturn(PETSC_SUCCESS); 3103 } 3104 3105 /*@ 3106 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3107 3108 Not Collective 3109 3110 Input Parameters: 3111 + dm - The `DMPLEX` 3112 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3113 3114 Output Parameters: 3115 + pConesSection - `PetscSection` describing the layout of `pCones` 3116 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3117 3118 Level: intermediate 3119 3120 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3121 @*/ 3122 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3123 { 3124 PetscSection cs, newcs; 3125 PetscInt *cones; 3126 PetscInt *newarr = NULL; 3127 PetscInt n; 3128 3129 PetscFunctionBegin; 3130 PetscCall(DMPlexGetCones(dm, &cones)); 3131 PetscCall(DMPlexGetConeSection(dm, &cs)); 3132 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3133 if (pConesSection) *pConesSection = newcs; 3134 if (pCones) { 3135 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3136 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3137 } 3138 PetscFunctionReturn(PETSC_SUCCESS); 3139 } 3140 3141 /*@ 3142 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3143 3144 Not Collective 3145 3146 Input Parameters: 3147 + dm - The `DMPLEX` 3148 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3149 3150 Output Parameter: 3151 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3152 3153 Level: advanced 3154 3155 Notes: 3156 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3157 3158 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3159 3160 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3161 `DMPlexGetDepth()`, `IS` 3162 @*/ 3163 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3164 { 3165 IS *expandedPointsAll; 3166 PetscInt depth; 3167 3168 PetscFunctionBegin; 3169 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3170 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3171 PetscAssertPointer(expandedPoints, 3); 3172 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3173 *expandedPoints = expandedPointsAll[0]; 3174 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3175 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3176 PetscFunctionReturn(PETSC_SUCCESS); 3177 } 3178 3179 /*@ 3180 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3181 (DAG points of depth 0, i.e., without cones). 3182 3183 Not Collective 3184 3185 Input Parameters: 3186 + dm - The `DMPLEX` 3187 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3188 3189 Output Parameters: 3190 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3191 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3192 - sections - (optional) An array of sections which describe mappings from points to their cone points 3193 3194 Level: advanced 3195 3196 Notes: 3197 Like `DMPlexGetConeTuple()` but recursive. 3198 3199 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. 3200 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3201 3202 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\: 3203 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3204 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3205 3206 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3207 `DMPlexGetDepth()`, `PetscSection`, `IS` 3208 @*/ 3209 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3210 { 3211 const PetscInt *arr0 = NULL, *cone = NULL; 3212 PetscInt *arr = NULL, *newarr = NULL; 3213 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3214 IS *expandedPoints_; 3215 PetscSection *sections_; 3216 3217 PetscFunctionBegin; 3218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3219 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3220 if (depth) PetscAssertPointer(depth, 3); 3221 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3222 if (sections) PetscAssertPointer(sections, 5); 3223 PetscCall(ISGetLocalSize(points, &n)); 3224 PetscCall(ISGetIndices(points, &arr0)); 3225 PetscCall(DMPlexGetDepth(dm, &depth_)); 3226 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3227 PetscCall(PetscCalloc1(depth_, §ions_)); 3228 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3229 for (d = depth_ - 1; d >= 0; d--) { 3230 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3231 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3232 for (i = 0; i < n; i++) { 3233 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3234 if (arr[i] >= start && arr[i] < end) { 3235 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3236 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3237 } else { 3238 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3239 } 3240 } 3241 PetscCall(PetscSectionSetUp(sections_[d])); 3242 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3243 PetscCall(PetscMalloc1(newn, &newarr)); 3244 for (i = 0; i < n; i++) { 3245 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3246 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3247 if (cn > 1) { 3248 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3249 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3250 } else { 3251 newarr[co] = arr[i]; 3252 } 3253 } 3254 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3255 arr = newarr; 3256 n = newn; 3257 } 3258 PetscCall(ISRestoreIndices(points, &arr0)); 3259 *depth = depth_; 3260 if (expandedPoints) *expandedPoints = expandedPoints_; 3261 else { 3262 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3263 PetscCall(PetscFree(expandedPoints_)); 3264 } 3265 if (sections) *sections = sections_; 3266 else { 3267 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3268 PetscCall(PetscFree(sections_)); 3269 } 3270 PetscFunctionReturn(PETSC_SUCCESS); 3271 } 3272 3273 /*@ 3274 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3275 3276 Not Collective 3277 3278 Input Parameters: 3279 + dm - The `DMPLEX` 3280 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3281 3282 Output Parameters: 3283 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3284 . expandedPoints - (optional) An array of recursively expanded cones 3285 - sections - (optional) An array of sections which describe mappings from points to their cone points 3286 3287 Level: advanced 3288 3289 Note: 3290 See `DMPlexGetConeRecursive()` 3291 3292 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3293 `DMPlexGetDepth()`, `IS`, `PetscSection` 3294 @*/ 3295 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3296 { 3297 PetscInt d, depth_; 3298 3299 PetscFunctionBegin; 3300 PetscCall(DMPlexGetDepth(dm, &depth_)); 3301 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3302 if (depth) *depth = 0; 3303 if (expandedPoints) { 3304 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3305 PetscCall(PetscFree(*expandedPoints)); 3306 } 3307 if (sections) { 3308 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3309 PetscCall(PetscFree(*sections)); 3310 } 3311 PetscFunctionReturn(PETSC_SUCCESS); 3312 } 3313 3314 /*@ 3315 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 3316 3317 Not Collective 3318 3319 Input Parameters: 3320 + dm - The `DMPLEX` 3321 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3322 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3323 3324 Level: beginner 3325 3326 Note: 3327 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3328 3329 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3330 @*/ 3331 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3332 { 3333 DM_Plex *mesh = (DM_Plex *)dm->data; 3334 PetscInt dof, off, c; 3335 3336 PetscFunctionBegin; 3337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3338 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3339 if (dof) PetscAssertPointer(cone, 3); 3340 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3341 if (PetscDefined(USE_DEBUG)) { 3342 PetscInt pStart, pEnd; 3343 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3344 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); 3345 for (c = 0; c < dof; ++c) { 3346 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); 3347 mesh->cones[off + c] = cone[c]; 3348 } 3349 } else { 3350 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3351 } 3352 PetscFunctionReturn(PETSC_SUCCESS); 3353 } 3354 3355 /*@C 3356 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3357 3358 Not Collective 3359 3360 Input Parameters: 3361 + dm - The `DMPLEX` 3362 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3363 3364 Output Parameter: 3365 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3366 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3367 3368 Level: beginner 3369 3370 Note: 3371 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3372 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3373 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3374 with the identity. 3375 3376 Fortran Notes: 3377 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3378 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3379 3380 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3381 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3382 @*/ 3383 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3384 { 3385 DM_Plex *mesh = (DM_Plex *)dm->data; 3386 PetscInt off; 3387 3388 PetscFunctionBegin; 3389 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3390 if (PetscDefined(USE_DEBUG)) { 3391 PetscInt dof; 3392 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3393 if (dof) PetscAssertPointer(coneOrientation, 3); 3394 } 3395 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3396 3397 *coneOrientation = &mesh->coneOrientations[off]; 3398 PetscFunctionReturn(PETSC_SUCCESS); 3399 } 3400 3401 /*@ 3402 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3403 3404 Not Collective 3405 3406 Input Parameters: 3407 + dm - The `DMPLEX` 3408 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3409 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3410 3411 Level: beginner 3412 3413 Notes: 3414 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3415 3416 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3417 3418 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3419 @*/ 3420 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3421 { 3422 DM_Plex *mesh = (DM_Plex *)dm->data; 3423 PetscInt pStart, pEnd; 3424 PetscInt dof, off, c; 3425 3426 PetscFunctionBegin; 3427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3428 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3429 if (dof) PetscAssertPointer(coneOrientation, 3); 3430 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3431 if (PetscDefined(USE_DEBUG)) { 3432 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3433 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); 3434 for (c = 0; c < dof; ++c) { 3435 PetscInt cdof, o = coneOrientation[c]; 3436 3437 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3438 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); 3439 mesh->coneOrientations[off + c] = o; 3440 } 3441 } else { 3442 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3443 } 3444 PetscFunctionReturn(PETSC_SUCCESS); 3445 } 3446 3447 /*@ 3448 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3449 3450 Not Collective 3451 3452 Input Parameters: 3453 + dm - The `DMPLEX` 3454 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3455 . conePos - The local index in the cone where the point should be put 3456 - conePoint - The mesh point to insert 3457 3458 Level: beginner 3459 3460 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3461 @*/ 3462 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3463 { 3464 DM_Plex *mesh = (DM_Plex *)dm->data; 3465 PetscInt pStart, pEnd; 3466 PetscInt dof, off; 3467 3468 PetscFunctionBegin; 3469 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3470 if (PetscDefined(USE_DEBUG)) { 3471 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3472 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); 3473 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); 3474 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3475 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); 3476 } 3477 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3478 mesh->cones[off + conePos] = conePoint; 3479 PetscFunctionReturn(PETSC_SUCCESS); 3480 } 3481 3482 /*@ 3483 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3484 3485 Not Collective 3486 3487 Input Parameters: 3488 + dm - The `DMPLEX` 3489 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3490 . conePos - The local index in the cone where the point should be put 3491 - coneOrientation - The point orientation to insert 3492 3493 Level: beginner 3494 3495 Note: 3496 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3497 3498 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3499 @*/ 3500 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3501 { 3502 DM_Plex *mesh = (DM_Plex *)dm->data; 3503 PetscInt pStart, pEnd; 3504 PetscInt dof, off; 3505 3506 PetscFunctionBegin; 3507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3508 if (PetscDefined(USE_DEBUG)) { 3509 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3510 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); 3511 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3512 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); 3513 } 3514 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3515 mesh->coneOrientations[off + conePos] = coneOrientation; 3516 PetscFunctionReturn(PETSC_SUCCESS); 3517 } 3518 3519 /*@C 3520 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3521 3522 Not collective 3523 3524 Input Parameters: 3525 + dm - The DMPlex 3526 - p - The point, which must lie in the chart set with DMPlexSetChart() 3527 3528 Output Parameters: 3529 + cone - An array of points which are on the in-edges for point `p` 3530 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3531 integer giving the prescription for cone traversal. 3532 3533 Level: beginner 3534 3535 Notes: 3536 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3537 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3538 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3539 with the identity. 3540 3541 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3542 3543 Fortran Notes: 3544 `cone` and `ornt` must be declared with 3545 .vb 3546 PetscInt, pointer :: cone(:) 3547 PetscInt, pointer :: ornt(:) 3548 .ve 3549 3550 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3551 @*/ 3552 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3553 { 3554 DM_Plex *mesh = (DM_Plex *)dm->data; 3555 3556 PetscFunctionBegin; 3557 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3558 if (mesh->tr) { 3559 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3560 } else { 3561 PetscInt off; 3562 if (PetscDefined(USE_DEBUG)) { 3563 PetscInt dof; 3564 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3565 if (dof) { 3566 if (cone) PetscAssertPointer(cone, 3); 3567 if (ornt) PetscAssertPointer(ornt, 4); 3568 } 3569 } 3570 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3571 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3572 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3573 } 3574 PetscFunctionReturn(PETSC_SUCCESS); 3575 } 3576 3577 /*@C 3578 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3579 3580 Not Collective 3581 3582 Input Parameters: 3583 + dm - The DMPlex 3584 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3585 . cone - An array of points which are on the in-edges for point p 3586 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3587 integer giving the prescription for cone traversal. 3588 3589 Level: beginner 3590 3591 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3592 @*/ 3593 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3594 { 3595 DM_Plex *mesh = (DM_Plex *)dm->data; 3596 3597 PetscFunctionBegin; 3598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3599 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3600 PetscFunctionReturn(PETSC_SUCCESS); 3601 } 3602 3603 /*@ 3604 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3605 3606 Not Collective 3607 3608 Input Parameters: 3609 + dm - The `DMPLEX` 3610 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3611 3612 Output Parameter: 3613 . size - The support size for point `p` 3614 3615 Level: beginner 3616 3617 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3618 @*/ 3619 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3620 { 3621 DM_Plex *mesh = (DM_Plex *)dm->data; 3622 3623 PetscFunctionBegin; 3624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3625 PetscAssertPointer(size, 3); 3626 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3627 PetscFunctionReturn(PETSC_SUCCESS); 3628 } 3629 3630 /*@ 3631 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3632 3633 Not Collective 3634 3635 Input Parameters: 3636 + dm - The `DMPLEX` 3637 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3638 - size - The support size for point `p` 3639 3640 Level: beginner 3641 3642 Note: 3643 This should be called after `DMPlexSetChart()`. 3644 3645 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3646 @*/ 3647 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3648 { 3649 DM_Plex *mesh = (DM_Plex *)dm->data; 3650 3651 PetscFunctionBegin; 3652 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3653 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3654 PetscFunctionReturn(PETSC_SUCCESS); 3655 } 3656 3657 /*@C 3658 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3659 3660 Not Collective 3661 3662 Input Parameters: 3663 + dm - The `DMPLEX` 3664 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3665 3666 Output Parameter: 3667 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3668 3669 Level: beginner 3670 3671 Fortran Notes: 3672 `support` must be declared with 3673 .vb 3674 PetscInt, pointer :: support(:) 3675 .ve 3676 3677 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3678 `DMPlexRestoreSupport()` is not needed/available in C. 3679 3680 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3681 @*/ 3682 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3683 { 3684 DM_Plex *mesh = (DM_Plex *)dm->data; 3685 PetscInt off; 3686 3687 PetscFunctionBegin; 3688 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3689 PetscAssertPointer(support, 3); 3690 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3691 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3692 PetscFunctionReturn(PETSC_SUCCESS); 3693 } 3694 3695 /*@ 3696 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3697 3698 Not Collective 3699 3700 Input Parameters: 3701 + dm - The `DMPLEX` 3702 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3703 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3704 3705 Level: beginner 3706 3707 Note: 3708 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3709 3710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3711 @*/ 3712 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3713 { 3714 DM_Plex *mesh = (DM_Plex *)dm->data; 3715 PetscInt pStart, pEnd; 3716 PetscInt dof, off, c; 3717 3718 PetscFunctionBegin; 3719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3720 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3721 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3722 if (dof) PetscAssertPointer(support, 3); 3723 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3724 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); 3725 for (c = 0; c < dof; ++c) { 3726 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); 3727 mesh->supports[off + c] = support[c]; 3728 } 3729 PetscFunctionReturn(PETSC_SUCCESS); 3730 } 3731 3732 /*@ 3733 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3734 3735 Not Collective 3736 3737 Input Parameters: 3738 + dm - The `DMPLEX` 3739 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3740 . supportPos - The local index in the cone where the point should be put 3741 - supportPoint - The mesh point to insert 3742 3743 Level: beginner 3744 3745 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3746 @*/ 3747 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3748 { 3749 DM_Plex *mesh = (DM_Plex *)dm->data; 3750 PetscInt pStart, pEnd; 3751 PetscInt dof, off; 3752 3753 PetscFunctionBegin; 3754 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3755 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3756 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3757 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3758 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); 3759 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); 3760 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); 3761 mesh->supports[off + supportPos] = supportPoint; 3762 PetscFunctionReturn(PETSC_SUCCESS); 3763 } 3764 3765 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3766 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3767 { 3768 switch (ct) { 3769 case DM_POLYTOPE_SEGMENT: 3770 if (o == -1) return -2; 3771 break; 3772 case DM_POLYTOPE_TRIANGLE: 3773 if (o == -3) return -1; 3774 if (o == -2) return -3; 3775 if (o == -1) return -2; 3776 break; 3777 case DM_POLYTOPE_QUADRILATERAL: 3778 if (o == -4) return -2; 3779 if (o == -3) return -1; 3780 if (o == -2) return -4; 3781 if (o == -1) return -3; 3782 break; 3783 default: 3784 return o; 3785 } 3786 return o; 3787 } 3788 3789 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3790 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3791 { 3792 switch (ct) { 3793 case DM_POLYTOPE_SEGMENT: 3794 if ((o == -2) || (o == 1)) return -1; 3795 if (o == -1) return 0; 3796 break; 3797 case DM_POLYTOPE_TRIANGLE: 3798 if (o == -3) return -2; 3799 if (o == -2) return -1; 3800 if (o == -1) return -3; 3801 break; 3802 case DM_POLYTOPE_QUADRILATERAL: 3803 if (o == -4) return -2; 3804 if (o == -3) return -1; 3805 if (o == -2) return -4; 3806 if (o == -1) return -3; 3807 break; 3808 default: 3809 return o; 3810 } 3811 return o; 3812 } 3813 3814 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3815 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3816 { 3817 PetscInt pStart, pEnd, p; 3818 3819 PetscFunctionBegin; 3820 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3821 for (p = pStart; p < pEnd; ++p) { 3822 const PetscInt *cone, *ornt; 3823 PetscInt coneSize, c; 3824 3825 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3826 PetscCall(DMPlexGetCone(dm, p, &cone)); 3827 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3828 for (c = 0; c < coneSize; ++c) { 3829 DMPolytopeType ct; 3830 const PetscInt o = ornt[c]; 3831 3832 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3833 switch (ct) { 3834 case DM_POLYTOPE_SEGMENT: 3835 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3836 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3837 break; 3838 case DM_POLYTOPE_TRIANGLE: 3839 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3840 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3841 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3842 break; 3843 case DM_POLYTOPE_QUADRILATERAL: 3844 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3845 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3846 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3847 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3848 break; 3849 default: 3850 break; 3851 } 3852 } 3853 } 3854 PetscFunctionReturn(PETSC_SUCCESS); 3855 } 3856 3857 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3858 { 3859 DM_Plex *mesh = (DM_Plex *)dm->data; 3860 3861 PetscFunctionBeginHot; 3862 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3863 if (useCone) { 3864 PetscCall(DMPlexGetConeSize(dm, p, size)); 3865 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3866 } else { 3867 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3868 PetscCall(DMPlexGetSupport(dm, p, arr)); 3869 } 3870 } else { 3871 if (useCone) { 3872 const PetscSection s = mesh->coneSection; 3873 const PetscInt ps = p - s->pStart; 3874 const PetscInt off = s->atlasOff[ps]; 3875 3876 *size = s->atlasDof[ps]; 3877 *arr = mesh->cones + off; 3878 *ornt = mesh->coneOrientations + off; 3879 } else { 3880 const PetscSection s = mesh->supportSection; 3881 const PetscInt ps = p - s->pStart; 3882 const PetscInt off = s->atlasOff[ps]; 3883 3884 *size = s->atlasDof[ps]; 3885 *arr = mesh->supports + off; 3886 } 3887 } 3888 PetscFunctionReturn(PETSC_SUCCESS); 3889 } 3890 3891 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3892 { 3893 DM_Plex *mesh = (DM_Plex *)dm->data; 3894 3895 PetscFunctionBeginHot; 3896 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3897 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3898 } 3899 PetscFunctionReturn(PETSC_SUCCESS); 3900 } 3901 3902 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3903 { 3904 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3905 PetscInt *closure; 3906 const PetscInt *tmp = NULL, *tmpO = NULL; 3907 PetscInt off = 0, tmpSize, t; 3908 3909 PetscFunctionBeginHot; 3910 if (ornt) { 3911 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3912 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; 3913 } 3914 if (*points) { 3915 closure = *points; 3916 } else { 3917 PetscInt maxConeSize, maxSupportSize; 3918 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3919 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3920 } 3921 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3922 if (ct == DM_POLYTOPE_UNKNOWN) { 3923 closure[off++] = p; 3924 closure[off++] = 0; 3925 for (t = 0; t < tmpSize; ++t) { 3926 closure[off++] = tmp[t]; 3927 closure[off++] = tmpO ? tmpO[t] : 0; 3928 } 3929 } else { 3930 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3931 3932 /* We assume that cells with a valid type have faces with a valid type */ 3933 closure[off++] = p; 3934 closure[off++] = ornt; 3935 for (t = 0; t < tmpSize; ++t) { 3936 DMPolytopeType ft; 3937 3938 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3939 closure[off++] = tmp[arr[t]]; 3940 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3941 } 3942 } 3943 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3944 if (numPoints) *numPoints = tmpSize + 1; 3945 if (points) *points = closure; 3946 PetscFunctionReturn(PETSC_SUCCESS); 3947 } 3948 3949 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3950 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3951 { 3952 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3953 const PetscInt *cone, *ornt; 3954 PetscInt *pts, *closure = NULL; 3955 DMPolytopeType ft; 3956 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3957 PetscInt dim, coneSize, c, d, clSize, cl; 3958 3959 PetscFunctionBeginHot; 3960 PetscCall(DMGetDimension(dm, &dim)); 3961 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3962 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3963 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3964 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3965 maxSize = PetscMax(coneSeries, supportSeries); 3966 if (*points) { 3967 pts = *points; 3968 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3969 c = 0; 3970 pts[c++] = point; 3971 pts[c++] = o; 3972 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3973 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3974 for (cl = 0; cl < clSize * 2; cl += 2) { 3975 pts[c++] = closure[cl]; 3976 pts[c++] = closure[cl + 1]; 3977 } 3978 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3979 for (cl = 0; cl < clSize * 2; cl += 2) { 3980 pts[c++] = closure[cl]; 3981 pts[c++] = closure[cl + 1]; 3982 } 3983 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3984 for (d = 2; d < coneSize; ++d) { 3985 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3986 pts[c++] = cone[arr[d * 2 + 0]]; 3987 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3988 } 3989 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3990 if (dim >= 3) { 3991 for (d = 2; d < coneSize; ++d) { 3992 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3993 const PetscInt *fcone, *fornt; 3994 PetscInt fconeSize, fc, i; 3995 3996 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3997 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3998 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3999 for (fc = 0; fc < fconeSize; ++fc) { 4000 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4001 const PetscInt co = farr[fc * 2 + 1]; 4002 4003 for (i = 0; i < c; i += 2) 4004 if (pts[i] == cp) break; 4005 if (i == c) { 4006 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4007 pts[c++] = cp; 4008 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4009 } 4010 } 4011 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4012 } 4013 } 4014 *numPoints = c / 2; 4015 *points = pts; 4016 PetscFunctionReturn(PETSC_SUCCESS); 4017 } 4018 4019 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4020 { 4021 DMPolytopeType ct; 4022 PetscInt *closure, *fifo; 4023 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4024 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4025 PetscInt depth, maxSize; 4026 4027 PetscFunctionBeginHot; 4028 PetscCall(DMPlexGetDepth(dm, &depth)); 4029 if (depth == 1) { 4030 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4031 PetscFunctionReturn(PETSC_SUCCESS); 4032 } 4033 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4034 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; 4035 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4036 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4037 PetscFunctionReturn(PETSC_SUCCESS); 4038 } 4039 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4040 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4041 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4042 maxSize = PetscMax(coneSeries, supportSeries); 4043 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4044 if (*points) { 4045 closure = *points; 4046 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4047 closure[closureSize++] = p; 4048 closure[closureSize++] = ornt; 4049 fifo[fifoSize++] = p; 4050 fifo[fifoSize++] = ornt; 4051 fifo[fifoSize++] = ct; 4052 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4053 while (fifoSize - fifoStart) { 4054 const PetscInt q = fifo[fifoStart++]; 4055 const PetscInt o = fifo[fifoStart++]; 4056 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4057 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4058 const PetscInt *tmp, *tmpO = NULL; 4059 PetscInt tmpSize, t; 4060 4061 if (PetscDefined(USE_DEBUG)) { 4062 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4063 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); 4064 } 4065 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4066 for (t = 0; t < tmpSize; ++t) { 4067 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4068 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4069 const PetscInt cp = tmp[ip]; 4070 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4071 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4072 PetscInt c; 4073 4074 /* Check for duplicate */ 4075 for (c = 0; c < closureSize; c += 2) { 4076 if (closure[c] == cp) break; 4077 } 4078 if (c == closureSize) { 4079 closure[closureSize++] = cp; 4080 closure[closureSize++] = co; 4081 fifo[fifoSize++] = cp; 4082 fifo[fifoSize++] = co; 4083 fifo[fifoSize++] = ct; 4084 } 4085 } 4086 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4087 } 4088 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4089 if (numPoints) *numPoints = closureSize / 2; 4090 if (points) *points = closure; 4091 PetscFunctionReturn(PETSC_SUCCESS); 4092 } 4093 4094 /*@C 4095 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4096 4097 Not Collective 4098 4099 Input Parameters: 4100 + dm - The `DMPLEX` 4101 . p - The mesh point 4102 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4103 4104 Input/Output Parameter: 4105 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4106 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4107 otherwise the provided array is used to hold the values 4108 4109 Output Parameter: 4110 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4111 4112 Level: beginner 4113 4114 Note: 4115 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4116 4117 Fortran Notes: 4118 `points` must be declared with 4119 .vb 4120 PetscInt, pointer :: points(:) 4121 .ve 4122 and is always allocated by the function. 4123 4124 The `numPoints` argument is not present in the Fortran binding. 4125 4126 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4127 @*/ 4128 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4129 { 4130 PetscFunctionBeginHot; 4131 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4132 if (numPoints) PetscAssertPointer(numPoints, 4); 4133 if (points) PetscAssertPointer(points, 5); 4134 if (PetscDefined(USE_DEBUG)) { 4135 PetscInt pStart, pEnd; 4136 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4137 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); 4138 } 4139 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4140 PetscFunctionReturn(PETSC_SUCCESS); 4141 } 4142 4143 /*@C 4144 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4145 4146 Not Collective 4147 4148 Input Parameters: 4149 + dm - The `DMPLEX` 4150 . p - The mesh point 4151 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4152 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4153 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4154 4155 Level: beginner 4156 4157 Note: 4158 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4159 4160 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4161 @*/ 4162 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4163 { 4164 PetscFunctionBeginHot; 4165 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4166 if (numPoints) *numPoints = 0; 4167 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4168 PetscFunctionReturn(PETSC_SUCCESS); 4169 } 4170 4171 /*@ 4172 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4173 4174 Not Collective 4175 4176 Input Parameter: 4177 . dm - The `DMPLEX` 4178 4179 Output Parameters: 4180 + maxConeSize - The maximum number of in-edges 4181 - maxSupportSize - The maximum number of out-edges 4182 4183 Level: beginner 4184 4185 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4186 @*/ 4187 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4188 { 4189 DM_Plex *mesh = (DM_Plex *)dm->data; 4190 4191 PetscFunctionBegin; 4192 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4193 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4194 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4195 PetscFunctionReturn(PETSC_SUCCESS); 4196 } 4197 4198 PetscErrorCode DMSetUp_Plex(DM dm) 4199 { 4200 DM_Plex *mesh = (DM_Plex *)dm->data; 4201 PetscInt size, maxSupportSize; 4202 4203 PetscFunctionBegin; 4204 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4205 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4206 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4207 PetscCall(PetscMalloc1(size, &mesh->cones)); 4208 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4209 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4210 if (maxSupportSize) { 4211 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4212 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4213 PetscCall(PetscMalloc1(size, &mesh->supports)); 4214 } 4215 PetscFunctionReturn(PETSC_SUCCESS); 4216 } 4217 4218 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4219 { 4220 PetscFunctionBegin; 4221 if (subdm) PetscCall(DMClone(dm, subdm)); 4222 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4223 if (subdm) (*subdm)->useNatural = dm->useNatural; 4224 if (dm->useNatural && dm->sfMigration) { 4225 PetscSF sfNatural; 4226 4227 (*subdm)->sfMigration = dm->sfMigration; 4228 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4229 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4230 (*subdm)->sfNatural = sfNatural; 4231 } 4232 PetscFunctionReturn(PETSC_SUCCESS); 4233 } 4234 4235 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4236 { 4237 PetscInt i = 0; 4238 4239 PetscFunctionBegin; 4240 PetscCall(DMClone(dms[0], superdm)); 4241 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4242 (*superdm)->useNatural = PETSC_FALSE; 4243 for (i = 0; i < len; i++) { 4244 if (dms[i]->useNatural && dms[i]->sfMigration) { 4245 PetscSF sfNatural; 4246 4247 (*superdm)->sfMigration = dms[i]->sfMigration; 4248 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4249 (*superdm)->useNatural = PETSC_TRUE; 4250 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4251 (*superdm)->sfNatural = sfNatural; 4252 break; 4253 } 4254 } 4255 PetscFunctionReturn(PETSC_SUCCESS); 4256 } 4257 4258 /*@ 4259 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4260 4261 Not Collective 4262 4263 Input Parameter: 4264 . dm - The `DMPLEX` 4265 4266 Level: beginner 4267 4268 Note: 4269 This should be called after all calls to `DMPlexSetCone()` 4270 4271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4272 @*/ 4273 PetscErrorCode DMPlexSymmetrize(DM dm) 4274 { 4275 DM_Plex *mesh = (DM_Plex *)dm->data; 4276 PetscInt *offsets; 4277 PetscInt supportSize; 4278 PetscInt pStart, pEnd, p; 4279 4280 PetscFunctionBegin; 4281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4282 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4283 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4284 /* Calculate support sizes */ 4285 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4286 for (p = pStart; p < pEnd; ++p) { 4287 PetscInt dof, off, c; 4288 4289 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4290 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4291 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4292 } 4293 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4294 /* Calculate supports */ 4295 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4296 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4297 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4298 for (p = pStart; p < pEnd; ++p) { 4299 PetscInt dof, off, c; 4300 4301 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4302 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4303 for (c = off; c < off + dof; ++c) { 4304 const PetscInt q = mesh->cones[c]; 4305 PetscInt offS; 4306 4307 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4308 4309 mesh->supports[offS + offsets[q]] = p; 4310 ++offsets[q]; 4311 } 4312 } 4313 PetscCall(PetscFree(offsets)); 4314 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4315 PetscFunctionReturn(PETSC_SUCCESS); 4316 } 4317 4318 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4319 { 4320 IS stratumIS; 4321 4322 PetscFunctionBegin; 4323 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4324 if (PetscDefined(USE_DEBUG)) { 4325 PetscInt qStart, qEnd, numLevels, level; 4326 PetscBool overlap = PETSC_FALSE; 4327 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4328 for (level = 0; level < numLevels; level++) { 4329 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4330 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4331 overlap = PETSC_TRUE; 4332 break; 4333 } 4334 } 4335 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); 4336 } 4337 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4338 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4339 PetscCall(ISDestroy(&stratumIS)); 4340 PetscFunctionReturn(PETSC_SUCCESS); 4341 } 4342 4343 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4344 { 4345 PetscInt *pMin, *pMax; 4346 PetscInt pStart, pEnd; 4347 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4348 4349 PetscFunctionBegin; 4350 { 4351 DMLabel label2; 4352 4353 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4354 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4355 } 4356 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4357 for (PetscInt p = pStart; p < pEnd; ++p) { 4358 DMPolytopeType ct; 4359 4360 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4361 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4362 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4363 } 4364 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4365 for (PetscInt d = dmin; d <= dmax; ++d) { 4366 pMin[d] = PETSC_MAX_INT; 4367 pMax[d] = PETSC_MIN_INT; 4368 } 4369 for (PetscInt p = pStart; p < pEnd; ++p) { 4370 DMPolytopeType ct; 4371 PetscInt d; 4372 4373 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4374 d = DMPolytopeTypeGetDim(ct); 4375 pMin[d] = PetscMin(p, pMin[d]); 4376 pMax[d] = PetscMax(p, pMax[d]); 4377 } 4378 for (PetscInt d = dmin; d <= dmax; ++d) { 4379 if (pMin[d] > pMax[d]) continue; 4380 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4381 } 4382 PetscCall(PetscFree2(pMin, pMax)); 4383 PetscFunctionReturn(PETSC_SUCCESS); 4384 } 4385 4386 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4387 { 4388 PetscInt pStart, pEnd; 4389 PetscInt numRoots = 0, numLeaves = 0; 4390 4391 PetscFunctionBegin; 4392 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4393 { 4394 /* Initialize roots and count leaves */ 4395 PetscInt sMin = PETSC_MAX_INT; 4396 PetscInt sMax = PETSC_MIN_INT; 4397 PetscInt coneSize, supportSize; 4398 4399 for (PetscInt p = pStart; p < pEnd; ++p) { 4400 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4401 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4402 if (!coneSize && supportSize) { 4403 sMin = PetscMin(p, sMin); 4404 sMax = PetscMax(p, sMax); 4405 ++numRoots; 4406 } else if (!supportSize && coneSize) { 4407 ++numLeaves; 4408 } else if (!supportSize && !coneSize) { 4409 /* Isolated points */ 4410 sMin = PetscMin(p, sMin); 4411 sMax = PetscMax(p, sMax); 4412 } 4413 } 4414 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4415 } 4416 4417 if (numRoots + numLeaves == (pEnd - pStart)) { 4418 PetscInt sMin = PETSC_MAX_INT; 4419 PetscInt sMax = PETSC_MIN_INT; 4420 PetscInt coneSize, supportSize; 4421 4422 for (PetscInt p = pStart; p < pEnd; ++p) { 4423 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4424 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4425 if (!supportSize && coneSize) { 4426 sMin = PetscMin(p, sMin); 4427 sMax = PetscMax(p, sMax); 4428 } 4429 } 4430 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4431 } else { 4432 PetscInt level = 0; 4433 PetscInt qStart, qEnd; 4434 4435 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4436 while (qEnd > qStart) { 4437 PetscInt sMin = PETSC_MAX_INT; 4438 PetscInt sMax = PETSC_MIN_INT; 4439 4440 for (PetscInt q = qStart; q < qEnd; ++q) { 4441 const PetscInt *support; 4442 PetscInt supportSize; 4443 4444 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4445 PetscCall(DMPlexGetSupport(dm, q, &support)); 4446 for (PetscInt s = 0; s < supportSize; ++s) { 4447 sMin = PetscMin(support[s], sMin); 4448 sMax = PetscMax(support[s], sMax); 4449 } 4450 } 4451 PetscCall(DMLabelGetNumValues(label, &level)); 4452 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4453 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4454 } 4455 } 4456 PetscFunctionReturn(PETSC_SUCCESS); 4457 } 4458 4459 /*@ 4460 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4461 4462 Collective 4463 4464 Input Parameter: 4465 . dm - The `DMPLEX` 4466 4467 Level: beginner 4468 4469 Notes: 4470 The strata group all points of the same grade, and this function calculates the strata. This 4471 grade can be seen as the height (or depth) of the point in the DAG. 4472 4473 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4474 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4475 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4476 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4477 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4478 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4479 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4480 4481 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4482 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4483 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 4484 to interpolate only that one (e0), so that 4485 .vb 4486 cone(c0) = {e0, v2} 4487 cone(e0) = {v0, v1} 4488 .ve 4489 If `DMPlexStratify()` is run on this mesh, it will give depths 4490 .vb 4491 depth 0 = {v0, v1, v2} 4492 depth 1 = {e0, c0} 4493 .ve 4494 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4495 4496 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4497 4498 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4499 @*/ 4500 PetscErrorCode DMPlexStratify(DM dm) 4501 { 4502 DM_Plex *mesh = (DM_Plex *)dm->data; 4503 DMLabel label; 4504 PetscBool flg = PETSC_FALSE; 4505 4506 PetscFunctionBegin; 4507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4508 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4509 4510 // Create depth label 4511 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4512 PetscCall(DMCreateLabel(dm, "depth")); 4513 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4514 4515 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4516 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4517 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4518 4519 { /* just in case there is an empty process */ 4520 PetscInt numValues, maxValues = 0, v; 4521 4522 PetscCall(DMLabelGetNumValues(label, &numValues)); 4523 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4524 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4525 } 4526 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4527 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4528 PetscFunctionReturn(PETSC_SUCCESS); 4529 } 4530 4531 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4532 { 4533 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4534 PetscInt dim, depth, pheight, coneSize; 4535 4536 PetscFunctionBeginHot; 4537 PetscCall(DMGetDimension(dm, &dim)); 4538 PetscCall(DMPlexGetDepth(dm, &depth)); 4539 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4540 pheight = depth - pdepth; 4541 if (depth <= 1) { 4542 switch (pdepth) { 4543 case 0: 4544 ct = DM_POLYTOPE_POINT; 4545 break; 4546 case 1: 4547 switch (coneSize) { 4548 case 2: 4549 ct = DM_POLYTOPE_SEGMENT; 4550 break; 4551 case 3: 4552 ct = DM_POLYTOPE_TRIANGLE; 4553 break; 4554 case 4: 4555 switch (dim) { 4556 case 2: 4557 ct = DM_POLYTOPE_QUADRILATERAL; 4558 break; 4559 case 3: 4560 ct = DM_POLYTOPE_TETRAHEDRON; 4561 break; 4562 default: 4563 break; 4564 } 4565 break; 4566 case 5: 4567 ct = DM_POLYTOPE_PYRAMID; 4568 break; 4569 case 6: 4570 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4571 break; 4572 case 8: 4573 ct = DM_POLYTOPE_HEXAHEDRON; 4574 break; 4575 default: 4576 break; 4577 } 4578 } 4579 } else { 4580 if (pdepth == 0) { 4581 ct = DM_POLYTOPE_POINT; 4582 } else if (pheight == 0) { 4583 switch (dim) { 4584 case 1: 4585 switch (coneSize) { 4586 case 2: 4587 ct = DM_POLYTOPE_SEGMENT; 4588 break; 4589 default: 4590 break; 4591 } 4592 break; 4593 case 2: 4594 switch (coneSize) { 4595 case 3: 4596 ct = DM_POLYTOPE_TRIANGLE; 4597 break; 4598 case 4: 4599 ct = DM_POLYTOPE_QUADRILATERAL; 4600 break; 4601 default: 4602 break; 4603 } 4604 break; 4605 case 3: 4606 switch (coneSize) { 4607 case 4: 4608 ct = DM_POLYTOPE_TETRAHEDRON; 4609 break; 4610 case 5: { 4611 const PetscInt *cone; 4612 PetscInt faceConeSize; 4613 4614 PetscCall(DMPlexGetCone(dm, p, &cone)); 4615 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4616 switch (faceConeSize) { 4617 case 3: 4618 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4619 break; 4620 case 4: 4621 ct = DM_POLYTOPE_PYRAMID; 4622 break; 4623 } 4624 } break; 4625 case 6: 4626 ct = DM_POLYTOPE_HEXAHEDRON; 4627 break; 4628 default: 4629 break; 4630 } 4631 break; 4632 default: 4633 break; 4634 } 4635 } else if (pheight > 0) { 4636 switch (coneSize) { 4637 case 2: 4638 ct = DM_POLYTOPE_SEGMENT; 4639 break; 4640 case 3: 4641 ct = DM_POLYTOPE_TRIANGLE; 4642 break; 4643 case 4: 4644 ct = DM_POLYTOPE_QUADRILATERAL; 4645 break; 4646 default: 4647 break; 4648 } 4649 } 4650 } 4651 *pt = ct; 4652 PetscFunctionReturn(PETSC_SUCCESS); 4653 } 4654 4655 /*@ 4656 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4657 4658 Collective 4659 4660 Input Parameter: 4661 . dm - The `DMPLEX` 4662 4663 Level: developer 4664 4665 Note: 4666 This function is normally called automatically when a cell type is requested. It creates an 4667 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4668 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4669 4670 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4671 4672 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4673 @*/ 4674 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4675 { 4676 DM_Plex *mesh; 4677 DMLabel ctLabel; 4678 PetscInt pStart, pEnd, p; 4679 4680 PetscFunctionBegin; 4681 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4682 mesh = (DM_Plex *)dm->data; 4683 PetscCall(DMCreateLabel(dm, "celltype")); 4684 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4685 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4686 PetscCall(PetscFree(mesh->cellTypes)); 4687 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4688 for (p = pStart; p < pEnd; ++p) { 4689 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4690 PetscInt pdepth; 4691 4692 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4693 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4694 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]); 4695 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4696 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4697 } 4698 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4699 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4700 PetscFunctionReturn(PETSC_SUCCESS); 4701 } 4702 4703 /*@C 4704 DMPlexGetJoin - Get an array for the join of the set of points 4705 4706 Not Collective 4707 4708 Input Parameters: 4709 + dm - The `DMPLEX` object 4710 . numPoints - The number of input points for the join 4711 - points - The input points 4712 4713 Output Parameters: 4714 + numCoveredPoints - The number of points in the join 4715 - coveredPoints - The points in the join 4716 4717 Level: intermediate 4718 4719 Note: 4720 Currently, this is restricted to a single level join 4721 4722 Fortran Notes: 4723 `converedPoints` must be declared with 4724 .vb 4725 PetscInt, pointer :: coveredPints(:) 4726 .ve 4727 4728 The `numCoveredPoints` argument is not present in the Fortran binding. 4729 4730 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4731 @*/ 4732 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4733 { 4734 DM_Plex *mesh = (DM_Plex *)dm->data; 4735 PetscInt *join[2]; 4736 PetscInt joinSize, i = 0; 4737 PetscInt dof, off, p, c, m; 4738 PetscInt maxSupportSize; 4739 4740 PetscFunctionBegin; 4741 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4742 PetscAssertPointer(points, 3); 4743 PetscAssertPointer(numCoveredPoints, 4); 4744 PetscAssertPointer(coveredPoints, 5); 4745 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4746 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4747 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4748 /* Copy in support of first point */ 4749 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4750 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4751 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4752 /* Check each successive support */ 4753 for (p = 1; p < numPoints; ++p) { 4754 PetscInt newJoinSize = 0; 4755 4756 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4757 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4758 for (c = 0; c < dof; ++c) { 4759 const PetscInt point = mesh->supports[off + c]; 4760 4761 for (m = 0; m < joinSize; ++m) { 4762 if (point == join[i][m]) { 4763 join[1 - i][newJoinSize++] = point; 4764 break; 4765 } 4766 } 4767 } 4768 joinSize = newJoinSize; 4769 i = 1 - i; 4770 } 4771 *numCoveredPoints = joinSize; 4772 *coveredPoints = join[i]; 4773 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4774 PetscFunctionReturn(PETSC_SUCCESS); 4775 } 4776 4777 /*@C 4778 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4779 4780 Not Collective 4781 4782 Input Parameters: 4783 + dm - The `DMPLEX` object 4784 . numPoints - The number of input points for the join 4785 - points - The input points 4786 4787 Output Parameters: 4788 + numCoveredPoints - The number of points in the join 4789 - coveredPoints - The points in the join 4790 4791 Level: intermediate 4792 4793 Fortran Notes: 4794 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4795 4796 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4797 @*/ 4798 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4799 { 4800 PetscFunctionBegin; 4801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4802 if (points) PetscAssertPointer(points, 3); 4803 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4804 PetscAssertPointer(coveredPoints, 5); 4805 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4806 if (numCoveredPoints) *numCoveredPoints = 0; 4807 PetscFunctionReturn(PETSC_SUCCESS); 4808 } 4809 4810 /*@C 4811 DMPlexGetFullJoin - Get an array for the join of the set of points 4812 4813 Not Collective 4814 4815 Input Parameters: 4816 + dm - The `DMPLEX` object 4817 . numPoints - The number of input points for the join 4818 - points - The input points, its length is `numPoints` 4819 4820 Output Parameters: 4821 + numCoveredPoints - The number of points in the join 4822 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4823 4824 Level: intermediate 4825 4826 Fortran Notes: 4827 `points` and `converedPoints` must be declared with 4828 .vb 4829 PetscInt, pointer :: points(:) 4830 PetscInt, pointer :: coveredPints(:) 4831 .ve 4832 4833 The `numCoveredPoints` argument is not present in the Fortran binding. 4834 4835 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4836 @*/ 4837 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4838 { 4839 PetscInt *offsets, **closures; 4840 PetscInt *join[2]; 4841 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4842 PetscInt p, d, c, m, ms; 4843 4844 PetscFunctionBegin; 4845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4846 PetscAssertPointer(points, 3); 4847 PetscAssertPointer(numCoveredPoints, 4); 4848 PetscAssertPointer(coveredPoints, 5); 4849 4850 PetscCall(DMPlexGetDepth(dm, &depth)); 4851 PetscCall(PetscCalloc1(numPoints, &closures)); 4852 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4853 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4854 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4855 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4856 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4857 4858 for (p = 0; p < numPoints; ++p) { 4859 PetscInt closureSize; 4860 4861 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4862 4863 offsets[p * (depth + 2) + 0] = 0; 4864 for (d = 0; d < depth + 1; ++d) { 4865 PetscInt pStart, pEnd, i; 4866 4867 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4868 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4869 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4870 offsets[p * (depth + 2) + d + 1] = i; 4871 break; 4872 } 4873 } 4874 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4875 } 4876 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); 4877 } 4878 for (d = 0; d < depth + 1; ++d) { 4879 PetscInt dof; 4880 4881 /* Copy in support of first point */ 4882 dof = offsets[d + 1] - offsets[d]; 4883 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4884 /* Check each successive cone */ 4885 for (p = 1; p < numPoints && joinSize; ++p) { 4886 PetscInt newJoinSize = 0; 4887 4888 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4889 for (c = 0; c < dof; ++c) { 4890 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4891 4892 for (m = 0; m < joinSize; ++m) { 4893 if (point == join[i][m]) { 4894 join[1 - i][newJoinSize++] = point; 4895 break; 4896 } 4897 } 4898 } 4899 joinSize = newJoinSize; 4900 i = 1 - i; 4901 } 4902 if (joinSize) break; 4903 } 4904 *numCoveredPoints = joinSize; 4905 *coveredPoints = join[i]; 4906 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4907 PetscCall(PetscFree(closures)); 4908 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4909 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4910 PetscFunctionReturn(PETSC_SUCCESS); 4911 } 4912 4913 /*@C 4914 DMPlexGetMeet - Get an array for the meet of the set of points 4915 4916 Not Collective 4917 4918 Input Parameters: 4919 + dm - The `DMPLEX` object 4920 . numPoints - The number of input points for the meet 4921 - points - The input points, of length `numPoints` 4922 4923 Output Parameters: 4924 + numCoveringPoints - The number of points in the meet 4925 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4926 4927 Level: intermediate 4928 4929 Note: 4930 Currently, this is restricted to a single level meet 4931 4932 Fortran Notes: 4933 `coveringPoints` must be declared with 4934 .vb 4935 PetscInt, pointer :: coveringPoints(:) 4936 .ve 4937 4938 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4939 4940 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4941 @*/ 4942 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4943 { 4944 DM_Plex *mesh = (DM_Plex *)dm->data; 4945 PetscInt *meet[2]; 4946 PetscInt meetSize, i = 0; 4947 PetscInt dof, off, p, c, m; 4948 PetscInt maxConeSize; 4949 4950 PetscFunctionBegin; 4951 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4952 PetscAssertPointer(points, 3); 4953 PetscAssertPointer(numCoveringPoints, 4); 4954 PetscAssertPointer(coveringPoints, 5); 4955 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4956 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4957 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4958 /* Copy in cone of first point */ 4959 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4960 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4961 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4962 /* Check each successive cone */ 4963 for (p = 1; p < numPoints; ++p) { 4964 PetscInt newMeetSize = 0; 4965 4966 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4967 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4968 for (c = 0; c < dof; ++c) { 4969 const PetscInt point = mesh->cones[off + c]; 4970 4971 for (m = 0; m < meetSize; ++m) { 4972 if (point == meet[i][m]) { 4973 meet[1 - i][newMeetSize++] = point; 4974 break; 4975 } 4976 } 4977 } 4978 meetSize = newMeetSize; 4979 i = 1 - i; 4980 } 4981 *numCoveringPoints = meetSize; 4982 *coveringPoints = meet[i]; 4983 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4984 PetscFunctionReturn(PETSC_SUCCESS); 4985 } 4986 4987 /*@C 4988 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 4989 4990 Not Collective 4991 4992 Input Parameters: 4993 + dm - The `DMPLEX` object 4994 . numPoints - The number of input points for the meet 4995 - points - The input points 4996 4997 Output Parameters: 4998 + numCoveredPoints - The number of points in the meet 4999 - coveredPoints - The points in the meet 5000 5001 Level: intermediate 5002 5003 Fortran Notes: 5004 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5005 5006 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5007 @*/ 5008 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5009 { 5010 PetscFunctionBegin; 5011 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5012 if (points) PetscAssertPointer(points, 3); 5013 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5014 PetscAssertPointer(coveredPoints, 5); 5015 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5016 if (numCoveredPoints) *numCoveredPoints = 0; 5017 PetscFunctionReturn(PETSC_SUCCESS); 5018 } 5019 5020 /*@C 5021 DMPlexGetFullMeet - Get an array for the meet of the set of points 5022 5023 Not Collective 5024 5025 Input Parameters: 5026 + dm - The `DMPLEX` object 5027 . numPoints - The number of input points for the meet 5028 - points - The input points, of length `numPoints` 5029 5030 Output Parameters: 5031 + numCoveredPoints - The number of points in the meet 5032 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5033 5034 Level: intermediate 5035 5036 Fortran Notes: 5037 `points` and `coveredPoints` must be declared with 5038 .vb 5039 PetscInt, pointer :: points(:) 5040 PetscInt, pointer :: coveredPoints(:) 5041 .ve 5042 5043 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5044 5045 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5046 @*/ 5047 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5048 { 5049 PetscInt *offsets, **closures; 5050 PetscInt *meet[2]; 5051 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5052 PetscInt p, h, c, m, mc; 5053 5054 PetscFunctionBegin; 5055 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5056 PetscAssertPointer(points, 3); 5057 PetscAssertPointer(numCoveredPoints, 4); 5058 PetscAssertPointer(coveredPoints, 5); 5059 5060 PetscCall(DMPlexGetDepth(dm, &height)); 5061 PetscCall(PetscMalloc1(numPoints, &closures)); 5062 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5063 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5064 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5065 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5066 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5067 5068 for (p = 0; p < numPoints; ++p) { 5069 PetscInt closureSize; 5070 5071 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5072 5073 offsets[p * (height + 2) + 0] = 0; 5074 for (h = 0; h < height + 1; ++h) { 5075 PetscInt pStart, pEnd, i; 5076 5077 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5078 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5079 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5080 offsets[p * (height + 2) + h + 1] = i; 5081 break; 5082 } 5083 } 5084 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5085 } 5086 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); 5087 } 5088 for (h = 0; h < height + 1; ++h) { 5089 PetscInt dof; 5090 5091 /* Copy in cone of first point */ 5092 dof = offsets[h + 1] - offsets[h]; 5093 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5094 /* Check each successive cone */ 5095 for (p = 1; p < numPoints && meetSize; ++p) { 5096 PetscInt newMeetSize = 0; 5097 5098 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5099 for (c = 0; c < dof; ++c) { 5100 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5101 5102 for (m = 0; m < meetSize; ++m) { 5103 if (point == meet[i][m]) { 5104 meet[1 - i][newMeetSize++] = point; 5105 break; 5106 } 5107 } 5108 } 5109 meetSize = newMeetSize; 5110 i = 1 - i; 5111 } 5112 if (meetSize) break; 5113 } 5114 *numCoveredPoints = meetSize; 5115 *coveredPoints = meet[i]; 5116 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5117 PetscCall(PetscFree(closures)); 5118 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5119 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5120 PetscFunctionReturn(PETSC_SUCCESS); 5121 } 5122 5123 /*@ 5124 DMPlexEqual - Determine if two `DM` have the same topology 5125 5126 Not Collective 5127 5128 Input Parameters: 5129 + dmA - A `DMPLEX` object 5130 - dmB - A `DMPLEX` object 5131 5132 Output Parameter: 5133 . equal - `PETSC_TRUE` if the topologies are identical 5134 5135 Level: intermediate 5136 5137 Note: 5138 We are not solving graph isomorphism, so we do not permute. 5139 5140 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5141 @*/ 5142 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5143 { 5144 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5145 5146 PetscFunctionBegin; 5147 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5148 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5149 PetscAssertPointer(equal, 3); 5150 5151 *equal = PETSC_FALSE; 5152 PetscCall(DMPlexGetDepth(dmA, &depth)); 5153 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5154 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5155 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5156 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5157 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5158 for (p = pStart; p < pEnd; ++p) { 5159 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5160 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5161 5162 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5163 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5164 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5165 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5166 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5167 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5168 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5169 for (c = 0; c < coneSize; ++c) { 5170 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5171 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5172 } 5173 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5174 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5175 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5176 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5177 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5178 for (s = 0; s < supportSize; ++s) { 5179 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5180 } 5181 } 5182 *equal = PETSC_TRUE; 5183 PetscFunctionReturn(PETSC_SUCCESS); 5184 } 5185 5186 /*@ 5187 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5188 5189 Not Collective 5190 5191 Input Parameters: 5192 + dm - The `DMPLEX` 5193 . cellDim - The cell dimension 5194 - numCorners - The number of vertices on a cell 5195 5196 Output Parameter: 5197 . numFaceVertices - The number of vertices on a face 5198 5199 Level: developer 5200 5201 Note: 5202 Of course this can only work for a restricted set of symmetric shapes 5203 5204 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5205 @*/ 5206 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5207 { 5208 MPI_Comm comm; 5209 5210 PetscFunctionBegin; 5211 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5212 PetscAssertPointer(numFaceVertices, 4); 5213 switch (cellDim) { 5214 case 0: 5215 *numFaceVertices = 0; 5216 break; 5217 case 1: 5218 *numFaceVertices = 1; 5219 break; 5220 case 2: 5221 switch (numCorners) { 5222 case 3: /* triangle */ 5223 *numFaceVertices = 2; /* Edge has 2 vertices */ 5224 break; 5225 case 4: /* quadrilateral */ 5226 *numFaceVertices = 2; /* Edge has 2 vertices */ 5227 break; 5228 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5229 *numFaceVertices = 3; /* Edge has 3 vertices */ 5230 break; 5231 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5232 *numFaceVertices = 3; /* Edge has 3 vertices */ 5233 break; 5234 default: 5235 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5236 } 5237 break; 5238 case 3: 5239 switch (numCorners) { 5240 case 4: /* tetradehdron */ 5241 *numFaceVertices = 3; /* Face has 3 vertices */ 5242 break; 5243 case 6: /* tet cohesive cells */ 5244 *numFaceVertices = 4; /* Face has 4 vertices */ 5245 break; 5246 case 8: /* hexahedron */ 5247 *numFaceVertices = 4; /* Face has 4 vertices */ 5248 break; 5249 case 9: /* tet cohesive Lagrange cells */ 5250 *numFaceVertices = 6; /* Face has 6 vertices */ 5251 break; 5252 case 10: /* quadratic tetrahedron */ 5253 *numFaceVertices = 6; /* Face has 6 vertices */ 5254 break; 5255 case 12: /* hex cohesive Lagrange cells */ 5256 *numFaceVertices = 6; /* Face has 6 vertices */ 5257 break; 5258 case 18: /* quadratic tet cohesive Lagrange cells */ 5259 *numFaceVertices = 6; /* Face has 6 vertices */ 5260 break; 5261 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5262 *numFaceVertices = 9; /* Face has 9 vertices */ 5263 break; 5264 default: 5265 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5266 } 5267 break; 5268 default: 5269 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5270 } 5271 PetscFunctionReturn(PETSC_SUCCESS); 5272 } 5273 5274 /*@ 5275 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5276 5277 Not Collective 5278 5279 Input Parameter: 5280 . dm - The `DMPLEX` object 5281 5282 Output Parameter: 5283 . depthLabel - The `DMLabel` recording point depth 5284 5285 Level: developer 5286 5287 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5288 @*/ 5289 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5290 { 5291 PetscFunctionBegin; 5292 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5293 PetscAssertPointer(depthLabel, 2); 5294 *depthLabel = dm->depthLabel; 5295 PetscFunctionReturn(PETSC_SUCCESS); 5296 } 5297 5298 /*@ 5299 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5300 5301 Not Collective 5302 5303 Input Parameter: 5304 . dm - The `DMPLEX` object 5305 5306 Output Parameter: 5307 . depth - The number of strata (breadth first levels) in the DAG 5308 5309 Level: developer 5310 5311 Notes: 5312 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5313 5314 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5315 5316 An empty mesh gives -1. 5317 5318 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5319 @*/ 5320 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5321 { 5322 DM_Plex *mesh = (DM_Plex *)dm->data; 5323 DMLabel label; 5324 PetscInt d = -1; 5325 5326 PetscFunctionBegin; 5327 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5328 PetscAssertPointer(depth, 2); 5329 if (mesh->tr) { 5330 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5331 } else { 5332 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5333 // Allow missing depths 5334 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5335 *depth = d; 5336 } 5337 PetscFunctionReturn(PETSC_SUCCESS); 5338 } 5339 5340 /*@ 5341 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5342 5343 Not Collective 5344 5345 Input Parameters: 5346 + dm - The `DMPLEX` object 5347 - depth - The requested depth 5348 5349 Output Parameters: 5350 + start - The first point at this `depth` 5351 - end - One beyond the last point at this `depth` 5352 5353 Level: developer 5354 5355 Notes: 5356 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5357 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5358 higher dimension, e.g., "edges". 5359 5360 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5361 @*/ 5362 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5363 { 5364 DM_Plex *mesh = (DM_Plex *)dm->data; 5365 DMLabel label; 5366 PetscInt pStart, pEnd; 5367 5368 PetscFunctionBegin; 5369 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5370 if (start) { 5371 PetscAssertPointer(start, 3); 5372 *start = 0; 5373 } 5374 if (end) { 5375 PetscAssertPointer(end, 4); 5376 *end = 0; 5377 } 5378 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5379 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5380 if (depth < 0) { 5381 if (start) *start = pStart; 5382 if (end) *end = pEnd; 5383 PetscFunctionReturn(PETSC_SUCCESS); 5384 } 5385 if (mesh->tr) { 5386 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5387 } else { 5388 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5389 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5390 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5391 } 5392 PetscFunctionReturn(PETSC_SUCCESS); 5393 } 5394 5395 /*@ 5396 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5397 5398 Not Collective 5399 5400 Input Parameters: 5401 + dm - The `DMPLEX` object 5402 - height - The requested height 5403 5404 Output Parameters: 5405 + start - The first point at this `height` 5406 - end - One beyond the last point at this `height` 5407 5408 Level: developer 5409 5410 Notes: 5411 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5412 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5413 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5414 5415 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5416 @*/ 5417 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5418 { 5419 DMLabel label; 5420 PetscInt depth, pStart, pEnd; 5421 5422 PetscFunctionBegin; 5423 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5424 if (start) { 5425 PetscAssertPointer(start, 3); 5426 *start = 0; 5427 } 5428 if (end) { 5429 PetscAssertPointer(end, 4); 5430 *end = 0; 5431 } 5432 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5433 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5434 if (height < 0) { 5435 if (start) *start = pStart; 5436 if (end) *end = pEnd; 5437 PetscFunctionReturn(PETSC_SUCCESS); 5438 } 5439 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5440 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5441 else PetscCall(DMGetDimension(dm, &depth)); 5442 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5443 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5444 PetscFunctionReturn(PETSC_SUCCESS); 5445 } 5446 5447 /*@ 5448 DMPlexGetPointDepth - Get the `depth` of a given point 5449 5450 Not Collective 5451 5452 Input Parameters: 5453 + dm - The `DMPLEX` object 5454 - point - The point 5455 5456 Output Parameter: 5457 . depth - The depth of the `point` 5458 5459 Level: intermediate 5460 5461 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5462 @*/ 5463 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5464 { 5465 PetscFunctionBegin; 5466 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5467 PetscAssertPointer(depth, 3); 5468 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5469 PetscFunctionReturn(PETSC_SUCCESS); 5470 } 5471 5472 /*@ 5473 DMPlexGetPointHeight - Get the `height` of a given point 5474 5475 Not Collective 5476 5477 Input Parameters: 5478 + dm - The `DMPLEX` object 5479 - point - The point 5480 5481 Output Parameter: 5482 . height - The height of the `point` 5483 5484 Level: intermediate 5485 5486 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5487 @*/ 5488 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5489 { 5490 PetscInt n, pDepth; 5491 5492 PetscFunctionBegin; 5493 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5494 PetscAssertPointer(height, 3); 5495 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5496 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5497 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5498 PetscFunctionReturn(PETSC_SUCCESS); 5499 } 5500 5501 /*@ 5502 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5503 5504 Not Collective 5505 5506 Input Parameter: 5507 . dm - The `DMPLEX` object 5508 5509 Output Parameter: 5510 . celltypeLabel - The `DMLabel` recording cell polytope type 5511 5512 Level: developer 5513 5514 Note: 5515 This function will trigger automatica computation of cell types. This can be disabled by calling 5516 `DMCreateLabel`(dm, "celltype") beforehand. 5517 5518 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5519 @*/ 5520 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5521 { 5522 PetscFunctionBegin; 5523 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5524 PetscAssertPointer(celltypeLabel, 2); 5525 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5526 *celltypeLabel = dm->celltypeLabel; 5527 PetscFunctionReturn(PETSC_SUCCESS); 5528 } 5529 5530 /*@ 5531 DMPlexGetCellType - Get the polytope type of a given cell 5532 5533 Not Collective 5534 5535 Input Parameters: 5536 + dm - The `DMPLEX` object 5537 - cell - The cell 5538 5539 Output Parameter: 5540 . celltype - The polytope type of the cell 5541 5542 Level: intermediate 5543 5544 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5545 @*/ 5546 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5547 { 5548 DM_Plex *mesh = (DM_Plex *)dm->data; 5549 DMLabel label; 5550 PetscInt ct; 5551 5552 PetscFunctionBegin; 5553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5554 PetscAssertPointer(celltype, 3); 5555 if (mesh->tr) { 5556 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5557 } else { 5558 PetscInt pStart, pEnd; 5559 5560 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5561 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5562 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5563 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5564 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5565 for (PetscInt p = pStart; p < pEnd; p++) { 5566 PetscCall(DMLabelGetValue(label, p, &ct)); 5567 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5568 } 5569 } 5570 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5571 if (PetscDefined(USE_DEBUG)) { 5572 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5573 PetscCall(DMLabelGetValue(label, cell, &ct)); 5574 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5575 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5576 } 5577 } 5578 PetscFunctionReturn(PETSC_SUCCESS); 5579 } 5580 5581 /*@ 5582 DMPlexSetCellType - Set the polytope type of a given cell 5583 5584 Not Collective 5585 5586 Input Parameters: 5587 + dm - The `DMPLEX` object 5588 . cell - The cell 5589 - celltype - The polytope type of the cell 5590 5591 Level: advanced 5592 5593 Note: 5594 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5595 is executed. This function will override the computed type. However, if automatic classification will not succeed 5596 and a user wants to manually specify all types, the classification must be disabled by calling 5597 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5598 5599 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5600 @*/ 5601 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5602 { 5603 DM_Plex *mesh = (DM_Plex *)dm->data; 5604 DMLabel label; 5605 PetscInt pStart, pEnd; 5606 5607 PetscFunctionBegin; 5608 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5609 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5610 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5611 PetscCall(DMLabelSetValue(label, cell, celltype)); 5612 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5613 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5614 PetscFunctionReturn(PETSC_SUCCESS); 5615 } 5616 5617 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5618 { 5619 PetscSection section; 5620 PetscInt maxHeight; 5621 const char *prefix; 5622 5623 PetscFunctionBegin; 5624 PetscCall(DMClone(dm, cdm)); 5625 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5626 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5627 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5628 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5629 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5630 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5631 PetscCall(DMSetLocalSection(*cdm, section)); 5632 PetscCall(PetscSectionDestroy(§ion)); 5633 5634 PetscCall(DMSetNumFields(*cdm, 1)); 5635 PetscCall(DMCreateDS(*cdm)); 5636 (*cdm)->cloneOpts = PETSC_TRUE; 5637 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5638 PetscFunctionReturn(PETSC_SUCCESS); 5639 } 5640 5641 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5642 { 5643 Vec coordsLocal, cellCoordsLocal; 5644 DM coordsDM, cellCoordsDM; 5645 5646 PetscFunctionBegin; 5647 *field = NULL; 5648 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5649 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5650 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5651 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5652 if (coordsLocal && coordsDM) { 5653 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5654 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5655 } 5656 PetscFunctionReturn(PETSC_SUCCESS); 5657 } 5658 5659 /*@ 5660 DMPlexGetConeSection - Return a section which describes the layout of cone data 5661 5662 Not Collective 5663 5664 Input Parameter: 5665 . dm - The `DMPLEX` object 5666 5667 Output Parameter: 5668 . section - The `PetscSection` object 5669 5670 Level: developer 5671 5672 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5673 @*/ 5674 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5675 { 5676 DM_Plex *mesh = (DM_Plex *)dm->data; 5677 5678 PetscFunctionBegin; 5679 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5680 if (section) *section = mesh->coneSection; 5681 PetscFunctionReturn(PETSC_SUCCESS); 5682 } 5683 5684 /*@ 5685 DMPlexGetSupportSection - Return a section which describes the layout of support data 5686 5687 Not Collective 5688 5689 Input Parameter: 5690 . dm - The `DMPLEX` object 5691 5692 Output Parameter: 5693 . section - The `PetscSection` object 5694 5695 Level: developer 5696 5697 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5698 @*/ 5699 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5700 { 5701 DM_Plex *mesh = (DM_Plex *)dm->data; 5702 5703 PetscFunctionBegin; 5704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5705 if (section) *section = mesh->supportSection; 5706 PetscFunctionReturn(PETSC_SUCCESS); 5707 } 5708 5709 /*@C 5710 DMPlexGetCones - Return cone data 5711 5712 Not Collective 5713 5714 Input Parameter: 5715 . dm - The `DMPLEX` object 5716 5717 Output Parameter: 5718 . cones - The cone for each point 5719 5720 Level: developer 5721 5722 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5723 @*/ 5724 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5725 { 5726 DM_Plex *mesh = (DM_Plex *)dm->data; 5727 5728 PetscFunctionBegin; 5729 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5730 if (cones) *cones = mesh->cones; 5731 PetscFunctionReturn(PETSC_SUCCESS); 5732 } 5733 5734 /*@C 5735 DMPlexGetConeOrientations - Return cone orientation data 5736 5737 Not Collective 5738 5739 Input Parameter: 5740 . dm - The `DMPLEX` object 5741 5742 Output Parameter: 5743 . coneOrientations - The array of cone orientations for all points 5744 5745 Level: developer 5746 5747 Notes: 5748 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5749 as returned by `DMPlexGetConeOrientation()`. 5750 5751 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5752 5753 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5754 @*/ 5755 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5756 { 5757 DM_Plex *mesh = (DM_Plex *)dm->data; 5758 5759 PetscFunctionBegin; 5760 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5761 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5762 PetscFunctionReturn(PETSC_SUCCESS); 5763 } 5764 5765 /******************************** FEM Support **********************************/ 5766 5767 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5768 { 5769 PetscInt depth; 5770 5771 PetscFunctionBegin; 5772 PetscCall(DMPlexGetDepth(plex, &depth)); 5773 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5774 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5775 PetscFunctionReturn(PETSC_SUCCESS); 5776 } 5777 5778 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5779 { 5780 PetscInt depth; 5781 5782 PetscFunctionBegin; 5783 PetscCall(DMPlexGetDepth(plex, &depth)); 5784 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5785 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5786 PetscFunctionReturn(PETSC_SUCCESS); 5787 } 5788 5789 /* 5790 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5791 representing a line in the section. 5792 */ 5793 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5794 { 5795 PetscObject obj; 5796 PetscClassId id; 5797 PetscFE fe = NULL; 5798 5799 PetscFunctionBeginHot; 5800 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5801 PetscCall(DMGetField(dm, field, NULL, &obj)); 5802 PetscCall(PetscObjectGetClassId(obj, &id)); 5803 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5804 5805 if (!fe) { 5806 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5807 /* An order k SEM disc has k-1 dofs on an edge */ 5808 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5809 *k = *k / *Nc + 1; 5810 } else { 5811 PetscInt dual_space_size, dim; 5812 PetscDualSpace dsp; 5813 5814 PetscCall(DMGetDimension(dm, &dim)); 5815 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5816 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5817 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5818 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5819 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5820 } 5821 PetscFunctionReturn(PETSC_SUCCESS); 5822 } 5823 5824 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5825 { 5826 PetscFunctionBeginHot; 5827 if (tensor) { 5828 *dof = PetscPowInt(k + 1, dim); 5829 } else { 5830 switch (dim) { 5831 case 1: 5832 *dof = k + 1; 5833 break; 5834 case 2: 5835 *dof = ((k + 1) * (k + 2)) / 2; 5836 break; 5837 case 3: 5838 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5839 break; 5840 default: 5841 *dof = 0; 5842 } 5843 } 5844 PetscFunctionReturn(PETSC_SUCCESS); 5845 } 5846 5847 /*@ 5848 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5849 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5850 section provided (or the section of the `DM`). 5851 5852 Input Parameters: 5853 + dm - The `DM` 5854 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5855 - section - The `PetscSection` to reorder, or `NULL` for the default section 5856 5857 Example: 5858 A typical interpolated single-quad mesh might order points as 5859 .vb 5860 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5861 5862 v4 -- e6 -- v3 5863 | | 5864 e7 c0 e8 5865 | | 5866 v1 -- e5 -- v2 5867 .ve 5868 5869 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5870 dofs in the order of points, e.g., 5871 .vb 5872 c0 -> [0,1,2,3] 5873 v1 -> [4] 5874 ... 5875 e5 -> [8, 9] 5876 .ve 5877 5878 which corresponds to the dofs 5879 .vb 5880 6 10 11 7 5881 13 2 3 15 5882 12 0 1 14 5883 4 8 9 5 5884 .ve 5885 5886 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5887 .vb 5888 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5889 .ve 5890 5891 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5892 .vb 5893 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5894 .ve 5895 5896 Level: developer 5897 5898 Notes: 5899 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5900 degree of the basis. 5901 5902 This is required to run with libCEED. 5903 5904 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5905 @*/ 5906 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5907 { 5908 DMLabel label; 5909 PetscInt dim, depth = -1, eStart = -1, Nf; 5910 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5911 5912 PetscFunctionBegin; 5913 PetscCall(DMGetDimension(dm, &dim)); 5914 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5915 if (point < 0) { 5916 PetscInt sStart, sEnd; 5917 5918 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5919 point = sEnd - sStart ? sStart : point; 5920 } 5921 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5922 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5923 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5924 if (depth == 1) { 5925 eStart = point; 5926 } else if (depth == dim) { 5927 const PetscInt *cone; 5928 5929 PetscCall(DMPlexGetCone(dm, point, &cone)); 5930 if (dim == 2) eStart = cone[0]; 5931 else if (dim == 3) { 5932 const PetscInt *cone2; 5933 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5934 eStart = cone2[0]; 5935 } 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); 5936 } 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); 5937 5938 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5939 for (PetscInt d = 1; d <= dim; d++) { 5940 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5941 PetscInt *perm; 5942 5943 for (f = 0; f < Nf; ++f) { 5944 PetscInt dof; 5945 5946 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5947 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5948 if (!continuous && d < dim) continue; 5949 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5950 size += dof * Nc; 5951 } 5952 PetscCall(PetscMalloc1(size, &perm)); 5953 for (f = 0; f < Nf; ++f) { 5954 switch (d) { 5955 case 1: 5956 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5957 if (!continuous && d < dim) continue; 5958 /* 5959 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5960 We want [ vtx0; edge of length k-1; vtx1 ] 5961 */ 5962 if (continuous) { 5963 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5964 for (i = 0; i < k - 1; i++) 5965 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5966 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5967 foffset = offset; 5968 } else { 5969 PetscInt dof; 5970 5971 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5972 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5973 foffset = offset; 5974 } 5975 break; 5976 case 2: 5977 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5978 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5979 if (!continuous && d < dim) continue; 5980 /* The SEM order is 5981 5982 v_lb, {e_b}, v_rb, 5983 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5984 v_lt, reverse {e_t}, v_rt 5985 */ 5986 if (continuous) { 5987 const PetscInt of = 0; 5988 const PetscInt oeb = of + PetscSqr(k - 1); 5989 const PetscInt oer = oeb + (k - 1); 5990 const PetscInt oet = oer + (k - 1); 5991 const PetscInt oel = oet + (k - 1); 5992 const PetscInt ovlb = oel + (k - 1); 5993 const PetscInt ovrb = ovlb + 1; 5994 const PetscInt ovrt = ovrb + 1; 5995 const PetscInt ovlt = ovrt + 1; 5996 PetscInt o; 5997 5998 /* bottom */ 5999 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6000 for (o = oeb; o < oer; ++o) 6001 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6002 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6003 /* middle */ 6004 for (i = 0; i < k - 1; ++i) { 6005 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6006 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6007 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6008 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6009 } 6010 /* top */ 6011 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6012 for (o = oel - 1; o >= oet; --o) 6013 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6014 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6015 foffset = offset; 6016 } else { 6017 PetscInt dof; 6018 6019 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6020 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6021 foffset = offset; 6022 } 6023 break; 6024 case 3: 6025 /* The original hex closure is 6026 6027 {c, 6028 f_b, f_t, f_f, f_b, f_r, f_l, 6029 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6030 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6031 */ 6032 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6033 if (!continuous && d < dim) continue; 6034 /* The SEM order is 6035 Bottom Slice 6036 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6037 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6038 v_blb, {e_bb}, v_brb, 6039 6040 Middle Slice (j) 6041 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6042 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6043 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6044 6045 Top Slice 6046 v_tlf, {e_tf}, v_trf, 6047 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6048 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6049 */ 6050 if (continuous) { 6051 const PetscInt oc = 0; 6052 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6053 const PetscInt oft = ofb + PetscSqr(k - 1); 6054 const PetscInt off = oft + PetscSqr(k - 1); 6055 const PetscInt ofk = off + PetscSqr(k - 1); 6056 const PetscInt ofr = ofk + PetscSqr(k - 1); 6057 const PetscInt ofl = ofr + PetscSqr(k - 1); 6058 const PetscInt oebl = ofl + PetscSqr(k - 1); 6059 const PetscInt oebb = oebl + (k - 1); 6060 const PetscInt oebr = oebb + (k - 1); 6061 const PetscInt oebf = oebr + (k - 1); 6062 const PetscInt oetf = oebf + (k - 1); 6063 const PetscInt oetr = oetf + (k - 1); 6064 const PetscInt oetb = oetr + (k - 1); 6065 const PetscInt oetl = oetb + (k - 1); 6066 const PetscInt oerf = oetl + (k - 1); 6067 const PetscInt oelf = oerf + (k - 1); 6068 const PetscInt oelb = oelf + (k - 1); 6069 const PetscInt oerb = oelb + (k - 1); 6070 const PetscInt ovblf = oerb + (k - 1); 6071 const PetscInt ovblb = ovblf + 1; 6072 const PetscInt ovbrb = ovblb + 1; 6073 const PetscInt ovbrf = ovbrb + 1; 6074 const PetscInt ovtlf = ovbrf + 1; 6075 const PetscInt ovtrf = ovtlf + 1; 6076 const PetscInt ovtrb = ovtrf + 1; 6077 const PetscInt ovtlb = ovtrb + 1; 6078 PetscInt o, n; 6079 6080 /* Bottom Slice */ 6081 /* bottom */ 6082 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6083 for (o = oetf - 1; o >= oebf; --o) 6084 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6085 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6086 /* middle */ 6087 for (i = 0; i < k - 1; ++i) { 6088 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6089 for (n = 0; n < k - 1; ++n) { 6090 o = ofb + n * (k - 1) + i; 6091 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6092 } 6093 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6094 } 6095 /* top */ 6096 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6097 for (o = oebb; o < oebr; ++o) 6098 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6099 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6100 6101 /* Middle Slice */ 6102 for (j = 0; j < k - 1; ++j) { 6103 /* bottom */ 6104 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6105 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6106 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6107 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6108 /* middle */ 6109 for (i = 0; i < k - 1; ++i) { 6110 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6111 for (n = 0; n < k - 1; ++n) 6112 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6113 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6114 } 6115 /* top */ 6116 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6117 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6118 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6119 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6120 } 6121 6122 /* Top Slice */ 6123 /* bottom */ 6124 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6125 for (o = oetf; o < oetr; ++o) 6126 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6127 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6128 /* middle */ 6129 for (i = 0; i < k - 1; ++i) { 6130 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6131 for (n = 0; n < k - 1; ++n) 6132 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6133 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6134 } 6135 /* top */ 6136 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6137 for (o = oetl - 1; o >= oetb; --o) 6138 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6139 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6140 6141 foffset = offset; 6142 } else { 6143 PetscInt dof; 6144 6145 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6146 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6147 foffset = offset; 6148 } 6149 break; 6150 default: 6151 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6152 } 6153 } 6154 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6155 /* Check permutation */ 6156 { 6157 PetscInt *check; 6158 6159 PetscCall(PetscMalloc1(size, &check)); 6160 for (i = 0; i < size; ++i) { 6161 check[i] = -1; 6162 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6163 } 6164 for (i = 0; i < size; ++i) check[perm[i]] = i; 6165 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6166 PetscCall(PetscFree(check)); 6167 } 6168 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6169 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6170 PetscInt *loc_perm; 6171 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6172 for (PetscInt i = 0; i < size; i++) { 6173 loc_perm[i] = perm[i]; 6174 loc_perm[size + i] = size + perm[i]; 6175 } 6176 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6177 } 6178 } 6179 PetscFunctionReturn(PETSC_SUCCESS); 6180 } 6181 6182 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6183 { 6184 PetscDS prob; 6185 PetscInt depth, Nf, h; 6186 DMLabel label; 6187 6188 PetscFunctionBeginHot; 6189 PetscCall(DMGetDS(dm, &prob)); 6190 Nf = prob->Nf; 6191 label = dm->depthLabel; 6192 *dspace = NULL; 6193 if (field < Nf) { 6194 PetscObject disc = prob->disc[field]; 6195 6196 if (disc->classid == PETSCFE_CLASSID) { 6197 PetscDualSpace dsp; 6198 6199 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6200 PetscCall(DMLabelGetNumValues(label, &depth)); 6201 PetscCall(DMLabelGetValue(label, point, &h)); 6202 h = depth - 1 - h; 6203 if (h) { 6204 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6205 } else { 6206 *dspace = dsp; 6207 } 6208 } 6209 } 6210 PetscFunctionReturn(PETSC_SUCCESS); 6211 } 6212 6213 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6214 { 6215 PetscScalar *array; 6216 const PetscScalar *vArray; 6217 const PetscInt *cone, *coneO; 6218 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6219 6220 PetscFunctionBeginHot; 6221 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6222 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6223 PetscCall(DMPlexGetCone(dm, point, &cone)); 6224 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6225 if (!values || !*values) { 6226 if ((point >= pStart) && (point < pEnd)) { 6227 PetscInt dof; 6228 6229 PetscCall(PetscSectionGetDof(section, point, &dof)); 6230 size += dof; 6231 } 6232 for (p = 0; p < numPoints; ++p) { 6233 const PetscInt cp = cone[p]; 6234 PetscInt dof; 6235 6236 if ((cp < pStart) || (cp >= pEnd)) continue; 6237 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6238 size += dof; 6239 } 6240 if (!values) { 6241 if (csize) *csize = size; 6242 PetscFunctionReturn(PETSC_SUCCESS); 6243 } 6244 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6245 } else { 6246 array = *values; 6247 } 6248 size = 0; 6249 PetscCall(VecGetArrayRead(v, &vArray)); 6250 if ((point >= pStart) && (point < pEnd)) { 6251 PetscInt dof, off, d; 6252 const PetscScalar *varr; 6253 6254 PetscCall(PetscSectionGetDof(section, point, &dof)); 6255 PetscCall(PetscSectionGetOffset(section, point, &off)); 6256 varr = PetscSafePointerPlusOffset(vArray, off); 6257 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6258 size += dof; 6259 } 6260 for (p = 0; p < numPoints; ++p) { 6261 const PetscInt cp = cone[p]; 6262 PetscInt o = coneO[p]; 6263 PetscInt dof, off, d; 6264 const PetscScalar *varr; 6265 6266 if ((cp < pStart) || (cp >= pEnd)) continue; 6267 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6268 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6269 varr = PetscSafePointerPlusOffset(vArray, off); 6270 if (o >= 0) { 6271 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6272 } else { 6273 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6274 } 6275 size += dof; 6276 } 6277 PetscCall(VecRestoreArrayRead(v, &vArray)); 6278 if (!*values) { 6279 if (csize) *csize = size; 6280 *values = array; 6281 } else { 6282 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6283 *csize = size; 6284 } 6285 PetscFunctionReturn(PETSC_SUCCESS); 6286 } 6287 6288 /* Compress out points not in the section */ 6289 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6290 { 6291 const PetscInt np = *numPoints; 6292 PetscInt pStart, pEnd, p, q; 6293 6294 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6295 for (p = 0, q = 0; p < np; ++p) { 6296 const PetscInt r = points[p * 2]; 6297 if ((r >= pStart) && (r < pEnd)) { 6298 points[q * 2] = r; 6299 points[q * 2 + 1] = points[p * 2 + 1]; 6300 ++q; 6301 } 6302 } 6303 *numPoints = q; 6304 return PETSC_SUCCESS; 6305 } 6306 6307 /* Compressed closure does not apply closure permutation */ 6308 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6309 { 6310 const PetscInt *cla = NULL; 6311 PetscInt np, *pts = NULL; 6312 6313 PetscFunctionBeginHot; 6314 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6315 if (!ornt && *clPoints) { 6316 PetscInt dof, off; 6317 6318 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6319 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6320 PetscCall(ISGetIndices(*clPoints, &cla)); 6321 np = dof / 2; 6322 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6323 } else { 6324 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6325 PetscCall(CompressPoints_Private(section, &np, pts)); 6326 } 6327 *numPoints = np; 6328 *points = pts; 6329 *clp = cla; 6330 PetscFunctionReturn(PETSC_SUCCESS); 6331 } 6332 6333 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6334 { 6335 PetscFunctionBeginHot; 6336 if (!*clPoints) { 6337 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6338 } else { 6339 PetscCall(ISRestoreIndices(*clPoints, clp)); 6340 } 6341 *numPoints = 0; 6342 *points = NULL; 6343 *clSec = NULL; 6344 *clPoints = NULL; 6345 *clp = NULL; 6346 PetscFunctionReturn(PETSC_SUCCESS); 6347 } 6348 6349 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6350 { 6351 PetscInt offset = 0, p; 6352 const PetscInt **perms = NULL; 6353 const PetscScalar **flips = NULL; 6354 6355 PetscFunctionBeginHot; 6356 *size = 0; 6357 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6358 for (p = 0; p < numPoints; p++) { 6359 const PetscInt point = points[2 * p]; 6360 const PetscInt *perm = perms ? perms[p] : NULL; 6361 const PetscScalar *flip = flips ? flips[p] : NULL; 6362 PetscInt dof, off, d; 6363 const PetscScalar *varr; 6364 6365 PetscCall(PetscSectionGetDof(section, point, &dof)); 6366 PetscCall(PetscSectionGetOffset(section, point, &off)); 6367 varr = PetscSafePointerPlusOffset(vArray, off); 6368 if (clperm) { 6369 if (perm) { 6370 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6371 } else { 6372 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6373 } 6374 if (flip) { 6375 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6376 } 6377 } else { 6378 if (perm) { 6379 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6380 } else { 6381 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6382 } 6383 if (flip) { 6384 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6385 } 6386 } 6387 offset += dof; 6388 } 6389 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6390 *size = offset; 6391 PetscFunctionReturn(PETSC_SUCCESS); 6392 } 6393 6394 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[]) 6395 { 6396 PetscInt offset = 0, f; 6397 6398 PetscFunctionBeginHot; 6399 *size = 0; 6400 for (f = 0; f < numFields; ++f) { 6401 PetscInt p; 6402 const PetscInt **perms = NULL; 6403 const PetscScalar **flips = NULL; 6404 6405 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6406 for (p = 0; p < numPoints; p++) { 6407 const PetscInt point = points[2 * p]; 6408 PetscInt fdof, foff, b; 6409 const PetscScalar *varr; 6410 const PetscInt *perm = perms ? perms[p] : NULL; 6411 const PetscScalar *flip = flips ? flips[p] : NULL; 6412 6413 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6414 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6415 varr = &vArray[foff]; 6416 if (clperm) { 6417 if (perm) { 6418 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6419 } else { 6420 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6421 } 6422 if (flip) { 6423 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6424 } 6425 } else { 6426 if (perm) { 6427 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6428 } else { 6429 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6430 } 6431 if (flip) { 6432 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6433 } 6434 } 6435 offset += fdof; 6436 } 6437 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6438 } 6439 *size = offset; 6440 PetscFunctionReturn(PETSC_SUCCESS); 6441 } 6442 6443 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6444 { 6445 PetscSection clSection; 6446 IS clPoints; 6447 PetscInt *points = NULL; 6448 const PetscInt *clp, *perm = NULL; 6449 PetscInt depth, numFields, numPoints, asize; 6450 6451 PetscFunctionBeginHot; 6452 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6453 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6454 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6455 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6456 PetscCall(DMPlexGetDepth(dm, &depth)); 6457 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6458 if (depth == 1 && numFields < 2) { 6459 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6460 PetscFunctionReturn(PETSC_SUCCESS); 6461 } 6462 /* Get points */ 6463 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6464 /* Get sizes */ 6465 asize = 0; 6466 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6467 PetscInt dof; 6468 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6469 asize += dof; 6470 } 6471 if (values) { 6472 const PetscScalar *vArray; 6473 PetscInt size; 6474 6475 if (*values) { 6476 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); 6477 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6478 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6479 PetscCall(VecGetArrayRead(v, &vArray)); 6480 /* Get values */ 6481 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6482 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6483 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6484 /* Cleanup array */ 6485 PetscCall(VecRestoreArrayRead(v, &vArray)); 6486 } 6487 if (csize) *csize = asize; 6488 /* Cleanup points */ 6489 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6490 PetscFunctionReturn(PETSC_SUCCESS); 6491 } 6492 6493 /*@C 6494 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6495 6496 Not collective 6497 6498 Input Parameters: 6499 + dm - The `DM` 6500 . section - The section describing the layout in `v`, or `NULL` to use the default section 6501 . v - The local vector 6502 - point - The point in the `DM` 6503 6504 Input/Output Parameters: 6505 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6506 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6507 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6508 6509 Level: intermediate 6510 6511 Notes: 6512 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6513 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6514 assembly function, and a user may already have allocated storage for this operation. 6515 6516 A typical use could be 6517 .vb 6518 values = NULL; 6519 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6520 for (cl = 0; cl < clSize; ++cl) { 6521 <Compute on closure> 6522 } 6523 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6524 .ve 6525 or 6526 .vb 6527 PetscMalloc1(clMaxSize, &values); 6528 for (p = pStart; p < pEnd; ++p) { 6529 clSize = clMaxSize; 6530 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6531 for (cl = 0; cl < clSize; ++cl) { 6532 <Compute on closure> 6533 } 6534 } 6535 PetscFree(values); 6536 .ve 6537 6538 Fortran Notes: 6539 The `csize` argument is not present in the Fortran binding. 6540 6541 `values` must be declared with 6542 .vb 6543 PetscScalar,dimension(:),pointer :: values 6544 .ve 6545 and it will be allocated internally by PETSc to hold the values returned 6546 6547 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6548 @*/ 6549 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6550 { 6551 PetscFunctionBeginHot; 6552 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6553 PetscFunctionReturn(PETSC_SUCCESS); 6554 } 6555 6556 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6557 { 6558 DMLabel depthLabel; 6559 PetscSection clSection; 6560 IS clPoints; 6561 PetscScalar *array; 6562 const PetscScalar *vArray; 6563 PetscInt *points = NULL; 6564 const PetscInt *clp, *perm = NULL; 6565 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6566 6567 PetscFunctionBeginHot; 6568 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6569 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6570 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6571 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6572 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6573 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6574 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6575 if (mdepth == 1 && numFields < 2) { 6576 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6577 PetscFunctionReturn(PETSC_SUCCESS); 6578 } 6579 /* Get points */ 6580 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6581 for (clsize = 0, p = 0; p < Np; p++) { 6582 PetscInt dof; 6583 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6584 clsize += dof; 6585 } 6586 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6587 /* Filter points */ 6588 for (p = 0; p < numPoints * 2; p += 2) { 6589 PetscInt dep; 6590 6591 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6592 if (dep != depth) continue; 6593 points[Np * 2 + 0] = points[p]; 6594 points[Np * 2 + 1] = points[p + 1]; 6595 ++Np; 6596 } 6597 /* Get array */ 6598 if (!values || !*values) { 6599 PetscInt asize = 0, dof; 6600 6601 for (p = 0; p < Np * 2; p += 2) { 6602 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6603 asize += dof; 6604 } 6605 if (!values) { 6606 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6607 if (csize) *csize = asize; 6608 PetscFunctionReturn(PETSC_SUCCESS); 6609 } 6610 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6611 } else { 6612 array = *values; 6613 } 6614 PetscCall(VecGetArrayRead(v, &vArray)); 6615 /* Get values */ 6616 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6617 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6618 /* Cleanup points */ 6619 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6620 /* Cleanup array */ 6621 PetscCall(VecRestoreArrayRead(v, &vArray)); 6622 if (!*values) { 6623 if (csize) *csize = size; 6624 *values = array; 6625 } else { 6626 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6627 *csize = size; 6628 } 6629 PetscFunctionReturn(PETSC_SUCCESS); 6630 } 6631 6632 /*@C 6633 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6634 6635 Not collective 6636 6637 Input Parameters: 6638 + dm - The `DM` 6639 . section - The section describing the layout in `v`, or `NULL` to use the default section 6640 . v - The local vector 6641 . point - The point in the `DM` 6642 . csize - The number of values in the closure, or `NULL` 6643 - values - The array of values 6644 6645 Level: intermediate 6646 6647 Note: 6648 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6649 6650 Fortran Note: 6651 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6652 6653 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6654 @*/ 6655 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6656 { 6657 PetscInt size = 0; 6658 6659 PetscFunctionBegin; 6660 /* Should work without recalculating size */ 6661 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6662 *values = NULL; 6663 PetscFunctionReturn(PETSC_SUCCESS); 6664 } 6665 6666 static inline void add(PetscScalar *x, PetscScalar y) 6667 { 6668 *x += y; 6669 } 6670 static inline void insert(PetscScalar *x, PetscScalar y) 6671 { 6672 *x = y; 6673 } 6674 6675 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[]) 6676 { 6677 PetscInt cdof; /* The number of constraints on this point */ 6678 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6679 PetscScalar *a; 6680 PetscInt off, cind = 0, k; 6681 6682 PetscFunctionBegin; 6683 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6684 PetscCall(PetscSectionGetOffset(section, point, &off)); 6685 a = &array[off]; 6686 if (!cdof || setBC) { 6687 if (clperm) { 6688 if (perm) { 6689 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6690 } else { 6691 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6692 } 6693 } else { 6694 if (perm) { 6695 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6696 } else { 6697 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6698 } 6699 } 6700 } else { 6701 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6702 if (clperm) { 6703 if (perm) { 6704 for (k = 0; k < dof; ++k) { 6705 if ((cind < cdof) && (k == cdofs[cind])) { 6706 ++cind; 6707 continue; 6708 } 6709 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6710 } 6711 } else { 6712 for (k = 0; k < dof; ++k) { 6713 if ((cind < cdof) && (k == cdofs[cind])) { 6714 ++cind; 6715 continue; 6716 } 6717 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6718 } 6719 } 6720 } else { 6721 if (perm) { 6722 for (k = 0; k < dof; ++k) { 6723 if ((cind < cdof) && (k == cdofs[cind])) { 6724 ++cind; 6725 continue; 6726 } 6727 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6728 } 6729 } else { 6730 for (k = 0; k < dof; ++k) { 6731 if ((cind < cdof) && (k == cdofs[cind])) { 6732 ++cind; 6733 continue; 6734 } 6735 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6736 } 6737 } 6738 } 6739 } 6740 PetscFunctionReturn(PETSC_SUCCESS); 6741 } 6742 6743 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[]) 6744 { 6745 PetscInt cdof; /* The number of constraints on this point */ 6746 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6747 PetscScalar *a; 6748 PetscInt off, cind = 0, k; 6749 6750 PetscFunctionBegin; 6751 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6752 PetscCall(PetscSectionGetOffset(section, point, &off)); 6753 a = &array[off]; 6754 if (cdof) { 6755 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6756 if (clperm) { 6757 if (perm) { 6758 for (k = 0; k < dof; ++k) { 6759 if ((cind < cdof) && (k == cdofs[cind])) { 6760 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6761 cind++; 6762 } 6763 } 6764 } else { 6765 for (k = 0; k < dof; ++k) { 6766 if ((cind < cdof) && (k == cdofs[cind])) { 6767 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6768 cind++; 6769 } 6770 } 6771 } 6772 } else { 6773 if (perm) { 6774 for (k = 0; k < dof; ++k) { 6775 if ((cind < cdof) && (k == cdofs[cind])) { 6776 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6777 cind++; 6778 } 6779 } 6780 } else { 6781 for (k = 0; k < dof; ++k) { 6782 if ((cind < cdof) && (k == cdofs[cind])) { 6783 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6784 cind++; 6785 } 6786 } 6787 } 6788 } 6789 } 6790 PetscFunctionReturn(PETSC_SUCCESS); 6791 } 6792 6793 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[]) 6794 { 6795 PetscScalar *a; 6796 PetscInt fdof, foff, fcdof, foffset = *offset; 6797 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6798 PetscInt cind = 0, b; 6799 6800 PetscFunctionBegin; 6801 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6802 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6803 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6804 a = &array[foff]; 6805 if (!fcdof || setBC) { 6806 if (clperm) { 6807 if (perm) { 6808 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6809 } else { 6810 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6811 } 6812 } else { 6813 if (perm) { 6814 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6815 } else { 6816 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6817 } 6818 } 6819 } else { 6820 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6821 if (clperm) { 6822 if (perm) { 6823 for (b = 0; b < fdof; b++) { 6824 if ((cind < fcdof) && (b == fcdofs[cind])) { 6825 ++cind; 6826 continue; 6827 } 6828 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6829 } 6830 } else { 6831 for (b = 0; b < fdof; b++) { 6832 if ((cind < fcdof) && (b == fcdofs[cind])) { 6833 ++cind; 6834 continue; 6835 } 6836 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6837 } 6838 } 6839 } else { 6840 if (perm) { 6841 for (b = 0; b < fdof; b++) { 6842 if ((cind < fcdof) && (b == fcdofs[cind])) { 6843 ++cind; 6844 continue; 6845 } 6846 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6847 } 6848 } else { 6849 for (b = 0; b < fdof; b++) { 6850 if ((cind < fcdof) && (b == fcdofs[cind])) { 6851 ++cind; 6852 continue; 6853 } 6854 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6855 } 6856 } 6857 } 6858 } 6859 *offset += fdof; 6860 PetscFunctionReturn(PETSC_SUCCESS); 6861 } 6862 6863 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[]) 6864 { 6865 PetscScalar *a; 6866 PetscInt fdof, foff, fcdof, foffset = *offset; 6867 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6868 PetscInt Nc, cind = 0, ncind = 0, b; 6869 PetscBool ncSet, fcSet; 6870 6871 PetscFunctionBegin; 6872 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6873 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6874 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6875 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6876 a = &array[foff]; 6877 if (fcdof) { 6878 /* We just override fcdof and fcdofs with Ncc and comps */ 6879 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6880 if (clperm) { 6881 if (perm) { 6882 if (comps) { 6883 for (b = 0; b < fdof; b++) { 6884 ncSet = fcSet = PETSC_FALSE; 6885 if (b % Nc == comps[ncind]) { 6886 ncind = (ncind + 1) % Ncc; 6887 ncSet = PETSC_TRUE; 6888 } 6889 if ((cind < fcdof) && (b == fcdofs[cind])) { 6890 ++cind; 6891 fcSet = PETSC_TRUE; 6892 } 6893 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6894 } 6895 } else { 6896 for (b = 0; b < fdof; b++) { 6897 if ((cind < fcdof) && (b == fcdofs[cind])) { 6898 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6899 ++cind; 6900 } 6901 } 6902 } 6903 } else { 6904 if (comps) { 6905 for (b = 0; b < fdof; b++) { 6906 ncSet = fcSet = PETSC_FALSE; 6907 if (b % Nc == comps[ncind]) { 6908 ncind = (ncind + 1) % Ncc; 6909 ncSet = PETSC_TRUE; 6910 } 6911 if ((cind < fcdof) && (b == fcdofs[cind])) { 6912 ++cind; 6913 fcSet = PETSC_TRUE; 6914 } 6915 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6916 } 6917 } else { 6918 for (b = 0; b < fdof; b++) { 6919 if ((cind < fcdof) && (b == fcdofs[cind])) { 6920 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6921 ++cind; 6922 } 6923 } 6924 } 6925 } 6926 } else { 6927 if (perm) { 6928 if (comps) { 6929 for (b = 0; b < fdof; b++) { 6930 ncSet = fcSet = PETSC_FALSE; 6931 if (b % Nc == comps[ncind]) { 6932 ncind = (ncind + 1) % Ncc; 6933 ncSet = PETSC_TRUE; 6934 } 6935 if ((cind < fcdof) && (b == fcdofs[cind])) { 6936 ++cind; 6937 fcSet = PETSC_TRUE; 6938 } 6939 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6940 } 6941 } else { 6942 for (b = 0; b < fdof; b++) { 6943 if ((cind < fcdof) && (b == fcdofs[cind])) { 6944 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6945 ++cind; 6946 } 6947 } 6948 } 6949 } else { 6950 if (comps) { 6951 for (b = 0; b < fdof; b++) { 6952 ncSet = fcSet = PETSC_FALSE; 6953 if (b % Nc == comps[ncind]) { 6954 ncind = (ncind + 1) % Ncc; 6955 ncSet = PETSC_TRUE; 6956 } 6957 if ((cind < fcdof) && (b == fcdofs[cind])) { 6958 ++cind; 6959 fcSet = PETSC_TRUE; 6960 } 6961 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6962 } 6963 } else { 6964 for (b = 0; b < fdof; b++) { 6965 if ((cind < fcdof) && (b == fcdofs[cind])) { 6966 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6967 ++cind; 6968 } 6969 } 6970 } 6971 } 6972 } 6973 } 6974 *offset += fdof; 6975 PetscFunctionReturn(PETSC_SUCCESS); 6976 } 6977 6978 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6979 { 6980 PetscScalar *array; 6981 const PetscInt *cone, *coneO; 6982 PetscInt pStart, pEnd, p, numPoints, off, dof; 6983 6984 PetscFunctionBeginHot; 6985 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6986 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6987 PetscCall(DMPlexGetCone(dm, point, &cone)); 6988 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6989 PetscCall(VecGetArray(v, &array)); 6990 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6991 const PetscInt cp = !p ? point : cone[p - 1]; 6992 const PetscInt o = !p ? 0 : coneO[p - 1]; 6993 6994 if ((cp < pStart) || (cp >= pEnd)) { 6995 dof = 0; 6996 continue; 6997 } 6998 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6999 /* ADD_VALUES */ 7000 { 7001 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7002 PetscScalar *a; 7003 PetscInt cdof, coff, cind = 0, k; 7004 7005 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7006 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7007 a = &array[coff]; 7008 if (!cdof) { 7009 if (o >= 0) { 7010 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7011 } else { 7012 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7013 } 7014 } else { 7015 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7016 if (o >= 0) { 7017 for (k = 0; k < dof; ++k) { 7018 if ((cind < cdof) && (k == cdofs[cind])) { 7019 ++cind; 7020 continue; 7021 } 7022 a[k] += values[off + k]; 7023 } 7024 } else { 7025 for (k = 0; k < dof; ++k) { 7026 if ((cind < cdof) && (k == cdofs[cind])) { 7027 ++cind; 7028 continue; 7029 } 7030 a[k] += values[off + dof - k - 1]; 7031 } 7032 } 7033 } 7034 } 7035 } 7036 PetscCall(VecRestoreArray(v, &array)); 7037 PetscFunctionReturn(PETSC_SUCCESS); 7038 } 7039 7040 /*@C 7041 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7042 7043 Not collective 7044 7045 Input Parameters: 7046 + dm - The `DM` 7047 . section - The section describing the layout in `v`, or `NULL` to use the default section 7048 . v - The local vector 7049 . point - The point in the `DM` 7050 . values - The array of values 7051 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7052 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7053 7054 Level: intermediate 7055 7056 Note: 7057 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7058 7059 Fortran Note: 7060 `values` must be declared with 7061 .vb 7062 PetscScalar,dimension(:),pointer :: values 7063 .ve 7064 7065 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7066 @*/ 7067 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7068 { 7069 PetscSection clSection; 7070 IS clPoints; 7071 PetscScalar *array; 7072 PetscInt *points = NULL; 7073 const PetscInt *clp, *clperm = NULL; 7074 PetscInt depth, numFields, numPoints, p, clsize; 7075 7076 PetscFunctionBeginHot; 7077 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7078 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7079 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7080 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7081 PetscCall(DMPlexGetDepth(dm, &depth)); 7082 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7083 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7084 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7085 PetscFunctionReturn(PETSC_SUCCESS); 7086 } 7087 /* Get points */ 7088 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7089 for (clsize = 0, p = 0; p < numPoints; p++) { 7090 PetscInt dof; 7091 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7092 clsize += dof; 7093 } 7094 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7095 /* Get array */ 7096 PetscCall(VecGetArray(v, &array)); 7097 /* Get values */ 7098 if (numFields > 0) { 7099 PetscInt offset = 0, f; 7100 for (f = 0; f < numFields; ++f) { 7101 const PetscInt **perms = NULL; 7102 const PetscScalar **flips = NULL; 7103 7104 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7105 switch (mode) { 7106 case INSERT_VALUES: 7107 for (p = 0; p < numPoints; p++) { 7108 const PetscInt point = points[2 * p]; 7109 const PetscInt *perm = perms ? perms[p] : NULL; 7110 const PetscScalar *flip = flips ? flips[p] : NULL; 7111 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7112 } 7113 break; 7114 case INSERT_ALL_VALUES: 7115 for (p = 0; p < numPoints; p++) { 7116 const PetscInt point = points[2 * p]; 7117 const PetscInt *perm = perms ? perms[p] : NULL; 7118 const PetscScalar *flip = flips ? flips[p] : NULL; 7119 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7120 } 7121 break; 7122 case INSERT_BC_VALUES: 7123 for (p = 0; p < numPoints; p++) { 7124 const PetscInt point = points[2 * p]; 7125 const PetscInt *perm = perms ? perms[p] : NULL; 7126 const PetscScalar *flip = flips ? flips[p] : NULL; 7127 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7128 } 7129 break; 7130 case ADD_VALUES: 7131 for (p = 0; p < numPoints; p++) { 7132 const PetscInt point = points[2 * p]; 7133 const PetscInt *perm = perms ? perms[p] : NULL; 7134 const PetscScalar *flip = flips ? flips[p] : NULL; 7135 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7136 } 7137 break; 7138 case ADD_ALL_VALUES: 7139 for (p = 0; p < numPoints; p++) { 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(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7144 } 7145 break; 7146 case ADD_BC_VALUES: 7147 for (p = 0; p < numPoints; p++) { 7148 const PetscInt point = points[2 * p]; 7149 const PetscInt *perm = perms ? perms[p] : NULL; 7150 const PetscScalar *flip = flips ? flips[p] : NULL; 7151 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7152 } 7153 break; 7154 default: 7155 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7156 } 7157 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7158 } 7159 } else { 7160 PetscInt dof, off; 7161 const PetscInt **perms = NULL; 7162 const PetscScalar **flips = NULL; 7163 7164 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7165 switch (mode) { 7166 case INSERT_VALUES: 7167 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7168 const PetscInt point = points[2 * p]; 7169 const PetscInt *perm = perms ? perms[p] : NULL; 7170 const PetscScalar *flip = flips ? flips[p] : NULL; 7171 PetscCall(PetscSectionGetDof(section, point, &dof)); 7172 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7173 } 7174 break; 7175 case INSERT_ALL_VALUES: 7176 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7177 const PetscInt point = points[2 * p]; 7178 const PetscInt *perm = perms ? perms[p] : NULL; 7179 const PetscScalar *flip = flips ? flips[p] : NULL; 7180 PetscCall(PetscSectionGetDof(section, point, &dof)); 7181 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7182 } 7183 break; 7184 case INSERT_BC_VALUES: 7185 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7186 const PetscInt point = points[2 * p]; 7187 const PetscInt *perm = perms ? perms[p] : NULL; 7188 const PetscScalar *flip = flips ? flips[p] : NULL; 7189 PetscCall(PetscSectionGetDof(section, point, &dof)); 7190 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7191 } 7192 break; 7193 case ADD_VALUES: 7194 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7195 const PetscInt point = points[2 * p]; 7196 const PetscInt *perm = perms ? perms[p] : NULL; 7197 const PetscScalar *flip = flips ? flips[p] : NULL; 7198 PetscCall(PetscSectionGetDof(section, point, &dof)); 7199 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7200 } 7201 break; 7202 case ADD_ALL_VALUES: 7203 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7204 const PetscInt point = points[2 * p]; 7205 const PetscInt *perm = perms ? perms[p] : NULL; 7206 const PetscScalar *flip = flips ? flips[p] : NULL; 7207 PetscCall(PetscSectionGetDof(section, point, &dof)); 7208 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7209 } 7210 break; 7211 case ADD_BC_VALUES: 7212 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7213 const PetscInt point = points[2 * p]; 7214 const PetscInt *perm = perms ? perms[p] : NULL; 7215 const PetscScalar *flip = flips ? flips[p] : NULL; 7216 PetscCall(PetscSectionGetDof(section, point, &dof)); 7217 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7218 } 7219 break; 7220 default: 7221 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7222 } 7223 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7224 } 7225 /* Cleanup points */ 7226 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7227 /* Cleanup array */ 7228 PetscCall(VecRestoreArray(v, &array)); 7229 PetscFunctionReturn(PETSC_SUCCESS); 7230 } 7231 7232 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7233 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7234 { 7235 PetscFunctionBegin; 7236 *contains = PETSC_TRUE; 7237 if (label) { 7238 PetscInt fdof; 7239 7240 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7241 if (!*contains) { 7242 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7243 *offset += fdof; 7244 PetscFunctionReturn(PETSC_SUCCESS); 7245 } 7246 } 7247 PetscFunctionReturn(PETSC_SUCCESS); 7248 } 7249 7250 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7251 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) 7252 { 7253 PetscSection clSection; 7254 IS clPoints; 7255 PetscScalar *array; 7256 PetscInt *points = NULL; 7257 const PetscInt *clp; 7258 PetscInt numFields, numPoints, p; 7259 PetscInt offset = 0, f; 7260 7261 PetscFunctionBeginHot; 7262 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7263 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7264 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7265 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7266 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7267 /* Get points */ 7268 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7269 /* Get array */ 7270 PetscCall(VecGetArray(v, &array)); 7271 /* Get values */ 7272 for (f = 0; f < numFields; ++f) { 7273 const PetscInt **perms = NULL; 7274 const PetscScalar **flips = NULL; 7275 PetscBool contains; 7276 7277 if (!fieldActive[f]) { 7278 for (p = 0; p < numPoints * 2; p += 2) { 7279 PetscInt fdof; 7280 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7281 offset += fdof; 7282 } 7283 continue; 7284 } 7285 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7286 switch (mode) { 7287 case INSERT_VALUES: 7288 for (p = 0; p < numPoints; p++) { 7289 const PetscInt point = points[2 * p]; 7290 const PetscInt *perm = perms ? perms[p] : NULL; 7291 const PetscScalar *flip = flips ? flips[p] : NULL; 7292 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7293 if (!contains) continue; 7294 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7295 } 7296 break; 7297 case INSERT_ALL_VALUES: 7298 for (p = 0; p < numPoints; p++) { 7299 const PetscInt point = points[2 * p]; 7300 const PetscInt *perm = perms ? perms[p] : NULL; 7301 const PetscScalar *flip = flips ? flips[p] : NULL; 7302 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7303 if (!contains) continue; 7304 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7305 } 7306 break; 7307 case INSERT_BC_VALUES: 7308 for (p = 0; p < numPoints; p++) { 7309 const PetscInt point = points[2 * p]; 7310 const PetscInt *perm = perms ? perms[p] : NULL; 7311 const PetscScalar *flip = flips ? flips[p] : NULL; 7312 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7313 if (!contains) continue; 7314 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7315 } 7316 break; 7317 case ADD_VALUES: 7318 for (p = 0; p < numPoints; p++) { 7319 const PetscInt point = points[2 * p]; 7320 const PetscInt *perm = perms ? perms[p] : NULL; 7321 const PetscScalar *flip = flips ? flips[p] : NULL; 7322 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7323 if (!contains) continue; 7324 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7325 } 7326 break; 7327 case ADD_ALL_VALUES: 7328 for (p = 0; p < numPoints; p++) { 7329 const PetscInt point = points[2 * p]; 7330 const PetscInt *perm = perms ? perms[p] : NULL; 7331 const PetscScalar *flip = flips ? flips[p] : NULL; 7332 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7333 if (!contains) continue; 7334 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7335 } 7336 break; 7337 default: 7338 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7339 } 7340 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7341 } 7342 /* Cleanup points */ 7343 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7344 /* Cleanup array */ 7345 PetscCall(VecRestoreArray(v, &array)); 7346 PetscFunctionReturn(PETSC_SUCCESS); 7347 } 7348 7349 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7350 { 7351 PetscMPIInt rank; 7352 PetscInt i, j; 7353 7354 PetscFunctionBegin; 7355 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7356 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7357 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7358 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7359 numCIndices = numCIndices ? numCIndices : numRIndices; 7360 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7361 for (i = 0; i < numRIndices; i++) { 7362 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7363 for (j = 0; j < numCIndices; j++) { 7364 #if defined(PETSC_USE_COMPLEX) 7365 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7366 #else 7367 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7368 #endif 7369 } 7370 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7371 } 7372 PetscFunctionReturn(PETSC_SUCCESS); 7373 } 7374 7375 /* 7376 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7377 7378 Input Parameters: 7379 + section - The section for this data layout 7380 . islocal - Is the section (and thus indices being requested) local or global? 7381 . point - The point contributing dofs with these indices 7382 . off - The global offset of this point 7383 . loff - The local offset of each field 7384 . setBC - The flag determining whether to include indices of boundary values 7385 . perm - A permutation of the dofs on this point, or NULL 7386 - indperm - A permutation of the entire indices array, or NULL 7387 7388 Output Parameter: 7389 . indices - Indices for dofs on this point 7390 7391 Level: developer 7392 7393 Note: The indices could be local or global, depending on the value of 'off'. 7394 */ 7395 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7396 { 7397 PetscInt dof; /* The number of unknowns on this point */ 7398 PetscInt cdof; /* The number of constraints on this point */ 7399 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7400 PetscInt cind = 0, k; 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(PetscSectionGetDof(section, point, &dof)); 7405 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7406 if (!cdof || setBC) { 7407 for (k = 0; k < dof; ++k) { 7408 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7409 const PetscInt ind = indperm ? indperm[preind] : preind; 7410 7411 indices[ind] = off + k; 7412 } 7413 } else { 7414 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7415 for (k = 0; k < dof; ++k) { 7416 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7417 const PetscInt ind = indperm ? indperm[preind] : preind; 7418 7419 if ((cind < cdof) && (k == cdofs[cind])) { 7420 /* Insert check for returning constrained indices */ 7421 indices[ind] = -(off + k + 1); 7422 ++cind; 7423 } else { 7424 indices[ind] = off + k - (islocal ? 0 : cind); 7425 } 7426 } 7427 } 7428 *loff += dof; 7429 PetscFunctionReturn(PETSC_SUCCESS); 7430 } 7431 7432 /* 7433 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7434 7435 Input Parameters: 7436 + section - a section (global or local) 7437 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7438 . point - point within section 7439 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7440 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7441 . setBC - identify constrained (boundary condition) points via involution. 7442 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7443 . permsoff - offset 7444 - indperm - index permutation 7445 7446 Output Parameter: 7447 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7448 . indices - array to hold indices (as defined by section) of each dof associated with point 7449 7450 Notes: 7451 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7452 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7453 in the local vector. 7454 7455 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7456 significant). It is invalid to call with a global section and setBC=true. 7457 7458 Developer Note: 7459 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7460 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7461 offset could be obtained from the section instead of passing it explicitly as we do now. 7462 7463 Example: 7464 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7465 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7466 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7467 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. 7468 7469 Level: developer 7470 */ 7471 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[]) 7472 { 7473 PetscInt numFields, foff, f; 7474 7475 PetscFunctionBegin; 7476 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7477 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7478 for (f = 0, foff = 0; f < numFields; ++f) { 7479 PetscInt fdof, cfdof; 7480 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7481 PetscInt cind = 0, b; 7482 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7483 7484 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7485 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7486 if (!cfdof || setBC) { 7487 for (b = 0; b < fdof; ++b) { 7488 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7489 const PetscInt ind = indperm ? indperm[preind] : preind; 7490 7491 indices[ind] = off + foff + b; 7492 } 7493 } else { 7494 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7495 for (b = 0; b < fdof; ++b) { 7496 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7497 const PetscInt ind = indperm ? indperm[preind] : preind; 7498 7499 if ((cind < cfdof) && (b == fcdofs[cind])) { 7500 indices[ind] = -(off + foff + b + 1); 7501 ++cind; 7502 } else { 7503 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7504 } 7505 } 7506 } 7507 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7508 foffs[f] += fdof; 7509 } 7510 PetscFunctionReturn(PETSC_SUCCESS); 7511 } 7512 7513 /* 7514 This version believes the globalSection offsets for each field, rather than just the point offset 7515 7516 . foffs - The offset into 'indices' for each field, since it is segregated by field 7517 7518 Notes: 7519 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7520 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7521 */ 7522 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7523 { 7524 PetscInt numFields, foff, f; 7525 7526 PetscFunctionBegin; 7527 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7528 for (f = 0; f < numFields; ++f) { 7529 PetscInt fdof, cfdof; 7530 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7531 PetscInt cind = 0, b; 7532 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7533 7534 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7535 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7536 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7537 if (!cfdof) { 7538 for (b = 0; b < fdof; ++b) { 7539 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7540 const PetscInt ind = indperm ? indperm[preind] : preind; 7541 7542 indices[ind] = foff + b; 7543 } 7544 } else { 7545 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7546 for (b = 0; b < fdof; ++b) { 7547 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7548 const PetscInt ind = indperm ? indperm[preind] : preind; 7549 7550 if ((cind < cfdof) && (b == fcdofs[cind])) { 7551 indices[ind] = -(foff + b + 1); 7552 ++cind; 7553 } else { 7554 indices[ind] = foff + b - cind; 7555 } 7556 } 7557 } 7558 foffs[f] += fdof; 7559 } 7560 PetscFunctionReturn(PETSC_SUCCESS); 7561 } 7562 7563 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7564 { 7565 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7566 7567 PetscFunctionBegin; 7568 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7569 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7570 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7571 for (PetscInt p = 0; p < nPoints; p++) { 7572 PetscInt b = pnts[2 * p]; 7573 PetscInt bSecDof = 0, bOff; 7574 PetscInt cSecDof = 0; 7575 PetscSection indices_section; 7576 7577 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7578 if (!bSecDof) continue; 7579 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7580 indices_section = cSecDof > 0 ? cSec : section; 7581 if (numFields) { 7582 PetscInt fStart[32], fEnd[32]; 7583 7584 fStart[0] = 0; 7585 fEnd[0] = 0; 7586 for (PetscInt f = 0; f < numFields; f++) { 7587 PetscInt fDof = 0; 7588 7589 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7590 fStart[f + 1] = fStart[f] + fDof; 7591 fEnd[f + 1] = fStart[f + 1]; 7592 } 7593 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7594 // only apply permutations on one side 7595 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7596 for (PetscInt f = 0; f < numFields; f++) { 7597 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7598 } 7599 } else { 7600 PetscInt bEnd = 0; 7601 7602 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7603 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7604 7605 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7606 } 7607 } 7608 PetscFunctionReturn(PETSC_SUCCESS); 7609 } 7610 7611 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[]) 7612 { 7613 Mat cMat; 7614 PetscSection aSec, cSec; 7615 IS aIS; 7616 PetscInt aStart = -1, aEnd = -1; 7617 PetscInt sStart = -1, sEnd = -1; 7618 PetscInt cStart = -1, cEnd = -1; 7619 const PetscInt *anchors; 7620 PetscInt numFields, p; 7621 PetscInt newNumPoints = 0, newNumIndices = 0; 7622 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7623 PetscInt oldOffsets[32]; 7624 PetscInt newOffsets[32]; 7625 PetscInt oldOffsetsCopy[32]; 7626 PetscInt newOffsetsCopy[32]; 7627 PetscScalar *modMat = NULL; 7628 PetscBool anyConstrained = PETSC_FALSE; 7629 7630 PetscFunctionBegin; 7631 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7632 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7633 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7634 7635 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7636 /* if there are point-to-point constraints */ 7637 if (aSec) { 7638 PetscCall(PetscArrayzero(newOffsets, 32)); 7639 PetscCall(PetscArrayzero(oldOffsets, 32)); 7640 PetscCall(ISGetIndices(aIS, &anchors)); 7641 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7642 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7643 /* figure out how many points are going to be in the new element matrix 7644 * (we allow double counting, because it's all just going to be summed 7645 * into the global matrix anyway) */ 7646 for (p = 0; p < 2 * numPoints; p += 2) { 7647 PetscInt b = points[p]; 7648 PetscInt bDof = 0, bSecDof = 0; 7649 7650 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7651 if (!bSecDof) continue; 7652 7653 for (PetscInt f = 0; f < numFields; f++) { 7654 PetscInt fDof = 0; 7655 7656 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7657 oldOffsets[f + 1] += fDof; 7658 } 7659 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7660 if (bDof) { 7661 /* this point is constrained */ 7662 /* it is going to be replaced by its anchors */ 7663 PetscInt bOff, q; 7664 7665 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7666 for (q = 0; q < bDof; q++) { 7667 PetscInt a = anchors[bOff + q]; 7668 PetscInt aDof = 0; 7669 7670 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7671 if (aDof) { 7672 anyConstrained = PETSC_TRUE; 7673 newNumPoints += 1; 7674 } 7675 newNumIndices += aDof; 7676 for (PetscInt f = 0; f < numFields; ++f) { 7677 PetscInt fDof = 0; 7678 7679 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7680 newOffsets[f + 1] += fDof; 7681 } 7682 } 7683 } else { 7684 /* this point is not constrained */ 7685 newNumPoints++; 7686 newNumIndices += bSecDof; 7687 for (PetscInt f = 0; f < numFields; ++f) { 7688 PetscInt fDof; 7689 7690 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7691 newOffsets[f + 1] += fDof; 7692 } 7693 } 7694 } 7695 } 7696 if (!anyConstrained) { 7697 if (outNumPoints) *outNumPoints = 0; 7698 if (outNumIndices) *outNumIndices = 0; 7699 if (outPoints) *outPoints = NULL; 7700 if (outMat) *outMat = NULL; 7701 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7702 PetscFunctionReturn(PETSC_SUCCESS); 7703 } 7704 7705 if (outNumPoints) *outNumPoints = newNumPoints; 7706 if (outNumIndices) *outNumIndices = newNumIndices; 7707 7708 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7709 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7710 7711 if (!outPoints && !outMat) { 7712 if (offsets) { 7713 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7714 } 7715 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7716 PetscFunctionReturn(PETSC_SUCCESS); 7717 } 7718 7719 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7720 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7721 7722 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7723 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7724 7725 /* output arrays */ 7726 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7727 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7728 7729 // get the new Points 7730 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7731 PetscInt b = points[2 * p]; 7732 PetscInt bDof = 0, bSecDof = 0, bOff; 7733 7734 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7735 if (!bSecDof) continue; 7736 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7737 if (bDof) { 7738 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7739 for (PetscInt q = 0; q < bDof; q++) { 7740 PetscInt a = anchors[bOff + q], aDof = 0; 7741 7742 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7743 if (aDof) { 7744 newPoints[2 * newP] = a; 7745 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7746 newP++; 7747 } 7748 } 7749 } else { 7750 newPoints[2 * newP] = b; 7751 newPoints[2 * newP + 1] = points[2 * p + 1]; 7752 newP++; 7753 } 7754 } 7755 7756 if (outMat) { 7757 PetscScalar *tmpMat; 7758 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7759 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7760 7761 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7762 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7763 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7764 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7765 7766 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7767 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7768 7769 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7770 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7771 7772 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7773 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7774 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7775 // for each field, insert the anchor modification into modMat 7776 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7777 PetscInt fStart = oldOffsets[f]; 7778 PetscInt fNewStart = newOffsets[f]; 7779 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7780 PetscInt b = points[2 * p]; 7781 PetscInt bDof = 0, bSecDof = 0, bOff; 7782 7783 if (b >= sStart && b < sEnd) { 7784 if (numFields) { 7785 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7786 } else { 7787 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7788 } 7789 } 7790 if (!bSecDof) continue; 7791 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7792 if (bDof) { 7793 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7794 for (PetscInt q = 0; q < bDof; q++, newP++) { 7795 PetscInt a = anchors[bOff + q], aDof = 0; 7796 7797 if (a >= sStart && a < sEnd) { 7798 if (numFields) { 7799 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7800 } else { 7801 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7802 } 7803 } 7804 if (aDof) { 7805 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7806 for (PetscInt d = 0; d < bSecDof; d++) { 7807 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7808 } 7809 } 7810 oNew += aDof; 7811 } 7812 } else { 7813 // Insert the identity matrix in this block 7814 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7815 oNew += bSecDof; 7816 newP++; 7817 } 7818 o += bSecDof; 7819 } 7820 } 7821 7822 *outMat = modMat; 7823 7824 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7825 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7826 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7827 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7828 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7829 } 7830 PetscCall(ISRestoreIndices(aIS, &anchors)); 7831 7832 /* output */ 7833 if (outPoints) { 7834 *outPoints = newPoints; 7835 } else { 7836 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7837 } 7838 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7839 PetscFunctionReturn(PETSC_SUCCESS); 7840 } 7841 7842 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) 7843 { 7844 PetscScalar *modMat = NULL; 7845 PetscInt newNumIndices = -1; 7846 7847 PetscFunctionBegin; 7848 /* 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. 7849 modMat is that matrix C */ 7850 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7851 if (outNumIndices) *outNumIndices = newNumIndices; 7852 if (modMat) { 7853 const PetscScalar *newValues = values; 7854 7855 if (multiplyRight) { 7856 PetscScalar *newNewValues = NULL; 7857 PetscBLASInt M = newNumIndices; 7858 PetscBLASInt N = numRows; 7859 PetscBLASInt K = numIndices; 7860 PetscScalar a = 1.0, b = 0.0; 7861 7862 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); 7863 7864 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7865 // row-major to column-major conversion, right multiplication becomes left multiplication 7866 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7867 7868 numCols = newNumIndices; 7869 newValues = newNewValues; 7870 } 7871 7872 if (multiplyLeft) { 7873 PetscScalar *newNewValues = NULL; 7874 PetscBLASInt M = numCols; 7875 PetscBLASInt N = newNumIndices; 7876 PetscBLASInt K = numIndices; 7877 PetscScalar a = 1.0, b = 0.0; 7878 7879 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); 7880 7881 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7882 // row-major to column-major conversion, left multiplication becomes right multiplication 7883 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7884 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7885 newValues = newNewValues; 7886 } 7887 *outValues = (PetscScalar *)newValues; 7888 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7889 } 7890 PetscFunctionReturn(PETSC_SUCCESS); 7891 } 7892 7893 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) 7894 { 7895 PetscFunctionBegin; 7896 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7897 PetscFunctionReturn(PETSC_SUCCESS); 7898 } 7899 7900 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7901 { 7902 /* Closure ordering */ 7903 PetscSection clSection; 7904 IS clPoints; 7905 const PetscInt *clp; 7906 PetscInt *points; 7907 PetscInt Ncl, Ni = 0; 7908 7909 PetscFunctionBeginHot; 7910 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7911 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7912 PetscInt dof; 7913 7914 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7915 Ni += dof; 7916 } 7917 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7918 *closureSize = Ni; 7919 PetscFunctionReturn(PETSC_SUCCESS); 7920 } 7921 7922 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) 7923 { 7924 /* Closure ordering */ 7925 PetscSection clSection; 7926 IS clPoints; 7927 const PetscInt *clp; 7928 PetscInt *points; 7929 const PetscInt *clperm = NULL; 7930 /* Dof permutation and sign flips */ 7931 const PetscInt **perms[32] = {NULL}; 7932 const PetscScalar **flips[32] = {NULL}; 7933 PetscScalar *valCopy = NULL; 7934 /* Hanging node constraints */ 7935 PetscInt *pointsC = NULL; 7936 PetscScalar *valuesC = NULL; 7937 PetscInt NclC, NiC; 7938 7939 PetscInt *idx; 7940 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7941 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7942 PetscInt idxStart, idxEnd; 7943 PetscInt nRows, nCols; 7944 7945 PetscFunctionBeginHot; 7946 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7947 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7948 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7949 PetscAssertPointer(numRows, 6); 7950 PetscAssertPointer(numCols, 7); 7951 if (indices) PetscAssertPointer(indices, 8); 7952 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7953 if (values) PetscAssertPointer(values, 10); 7954 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7955 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7956 PetscCall(PetscArrayzero(offsets, 32)); 7957 /* 1) Get points in closure */ 7958 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7959 if (useClPerm) { 7960 PetscInt depth, clsize; 7961 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7962 for (clsize = 0, p = 0; p < Ncl; p++) { 7963 PetscInt dof; 7964 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7965 clsize += dof; 7966 } 7967 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7968 } 7969 /* 2) Get number of indices on these points and field offsets from section */ 7970 for (p = 0; p < Ncl * 2; p += 2) { 7971 PetscInt dof, fdof; 7972 7973 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7974 for (f = 0; f < Nf; ++f) { 7975 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7976 offsets[f + 1] += fdof; 7977 } 7978 Ni += dof; 7979 } 7980 if (*numRows == -1) *numRows = Ni; 7981 if (*numCols == -1) *numCols = Ni; 7982 nRows = *numRows; 7983 nCols = *numCols; 7984 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7985 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7986 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7987 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7988 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7989 for (f = 0; f < PetscMax(1, Nf); ++f) { 7990 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7991 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7992 /* may need to apply sign changes to the element matrix */ 7993 if (values && flips[f]) { 7994 PetscInt foffset = offsets[f]; 7995 7996 for (p = 0; p < Ncl; ++p) { 7997 PetscInt pnt = points[2 * p], fdof; 7998 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7999 8000 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8001 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8002 if (flip) { 8003 PetscInt i, j, k; 8004 8005 if (!valCopy) { 8006 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8007 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8008 *values = valCopy; 8009 } 8010 for (i = 0; i < fdof; ++i) { 8011 PetscScalar fval = flip[i]; 8012 8013 if (multiplyRight) { 8014 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8015 } 8016 if (multiplyLeft) { 8017 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8018 } 8019 } 8020 } 8021 foffset += fdof; 8022 } 8023 } 8024 } 8025 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8026 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8027 if (NclC) { 8028 if (multiplyRight) { *numCols = nCols = NiC; } 8029 if (multiplyLeft) { *numRows = nRows = NiC; } 8030 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8031 for (f = 0; f < PetscMax(1, Nf); ++f) { 8032 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8033 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8034 } 8035 for (f = 0; f < PetscMax(1, Nf); ++f) { 8036 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8037 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8038 } 8039 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8040 Ncl = NclC; 8041 Ni = NiC; 8042 points = pointsC; 8043 if (values) *values = valuesC; 8044 } 8045 /* 5) Calculate indices */ 8046 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8047 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8048 if (Nf) { 8049 PetscInt idxOff; 8050 PetscBool useFieldOffsets; 8051 8052 if (outOffsets) { 8053 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8054 } 8055 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8056 if (useFieldOffsets) { 8057 for (p = 0; p < Ncl; ++p) { 8058 const PetscInt pnt = points[p * 2]; 8059 8060 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8061 } 8062 } else { 8063 for (p = 0; p < Ncl; ++p) { 8064 const PetscInt pnt = points[p * 2]; 8065 8066 if (pnt < idxStart || pnt >= idxEnd) continue; 8067 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8068 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8069 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8070 * global section. */ 8071 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8072 } 8073 } 8074 } else { 8075 PetscInt off = 0, idxOff; 8076 8077 for (p = 0; p < Ncl; ++p) { 8078 const PetscInt pnt = points[p * 2]; 8079 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8080 8081 if (pnt < idxStart || pnt >= idxEnd) continue; 8082 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8083 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8084 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8085 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8086 } 8087 } 8088 /* 6) Cleanup */ 8089 for (f = 0; f < PetscMax(1, Nf); ++f) { 8090 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8091 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8092 } 8093 if (NclC) { 8094 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8095 } else { 8096 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8097 } 8098 8099 if (indices) *indices = idx; 8100 PetscFunctionReturn(PETSC_SUCCESS); 8101 } 8102 8103 /*@C 8104 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8105 8106 Not collective 8107 8108 Input Parameters: 8109 + dm - The `DM` 8110 . section - The `PetscSection` describing the points (a local section) 8111 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8112 . point - The point defining the closure 8113 - useClPerm - Use the closure point permutation if available 8114 8115 Output Parameters: 8116 + numIndices - The number of dof indices in the closure of point with the input sections 8117 . indices - The dof indices 8118 . outOffsets - Array to write the field offsets into, or `NULL` 8119 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8120 8121 Level: advanced 8122 8123 Notes: 8124 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8125 8126 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8127 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8128 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8129 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8130 indices (with the above semantics) are implied. 8131 8132 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8133 `PetscSection`, `DMGetGlobalSection()` 8134 @*/ 8135 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8136 { 8137 PetscInt numRows = -1, numCols = -1; 8138 8139 PetscFunctionBeginHot; 8140 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8141 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8142 *numIndices = numRows; 8143 PetscFunctionReturn(PETSC_SUCCESS); 8144 } 8145 8146 /*@C 8147 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8148 8149 Not collective 8150 8151 Input Parameters: 8152 + dm - The `DM` 8153 . section - The `PetscSection` describing the points (a local section) 8154 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8155 . point - The point defining the closure 8156 - useClPerm - Use the closure point permutation if available 8157 8158 Output Parameters: 8159 + numIndices - The number of dof indices in the closure of point with the input sections 8160 . indices - The dof indices 8161 . outOffsets - Array to write the field offsets into, or `NULL` 8162 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8163 8164 Level: advanced 8165 8166 Notes: 8167 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8168 8169 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8170 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8171 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8172 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8173 indices (with the above semantics) are implied. 8174 8175 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8176 @*/ 8177 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8178 { 8179 PetscFunctionBegin; 8180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8181 PetscAssertPointer(indices, 7); 8182 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8183 PetscFunctionReturn(PETSC_SUCCESS); 8184 } 8185 8186 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8187 { 8188 DM_Plex *mesh = (DM_Plex *)dm->data; 8189 PetscInt *indices; 8190 PetscInt numIndices; 8191 const PetscScalar *valuesOrig = values; 8192 PetscErrorCode ierr; 8193 8194 PetscFunctionBegin; 8195 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8196 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8197 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8198 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8199 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8200 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8201 8202 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8203 8204 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8205 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8206 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8207 if (ierr) { 8208 PetscMPIInt rank; 8209 8210 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8211 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8212 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8213 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8214 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8215 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8216 } 8217 if (mesh->printFEM > 1) { 8218 PetscInt i; 8219 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8220 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8221 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8222 } 8223 8224 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8225 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8226 PetscFunctionReturn(PETSC_SUCCESS); 8227 } 8228 8229 /*@C 8230 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8231 8232 Not collective 8233 8234 Input Parameters: 8235 + dm - The `DM` 8236 . section - The section describing the layout in `v`, or `NULL` to use the default section 8237 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8238 . A - The matrix 8239 . point - The point in the `DM` 8240 . values - The array of values 8241 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8242 8243 Level: intermediate 8244 8245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8246 @*/ 8247 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8248 { 8249 PetscFunctionBegin; 8250 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8251 PetscFunctionReturn(PETSC_SUCCESS); 8252 } 8253 8254 /*@C 8255 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8256 8257 Not collective 8258 8259 Input Parameters: 8260 + dmRow - The `DM` for the row fields 8261 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8262 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8263 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8264 . dmCol - The `DM` for the column fields 8265 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8266 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8267 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8268 . A - The matrix 8269 . point - The point in the `DM` 8270 . values - The array of values 8271 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8272 8273 Level: intermediate 8274 8275 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8276 @*/ 8277 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) 8278 { 8279 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8280 PetscInt *indicesRow, *indicesCol; 8281 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8282 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8283 8284 PetscErrorCode ierr; 8285 8286 PetscFunctionBegin; 8287 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8288 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8289 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8290 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8291 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8292 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8293 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8294 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8295 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8296 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8297 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8298 8299 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8300 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8301 valuesV1 = valuesV0; 8302 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8303 valuesV2 = valuesV1; 8304 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8305 8306 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8307 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8308 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8309 if (ierr) { 8310 PetscMPIInt rank; 8311 8312 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8313 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8314 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8315 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8316 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8317 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8318 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8319 } 8320 8321 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8322 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8323 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8324 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8325 PetscFunctionReturn(PETSC_SUCCESS); 8326 } 8327 8328 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8329 { 8330 DM_Plex *mesh = (DM_Plex *)dmf->data; 8331 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8332 PetscInt *cpoints = NULL; 8333 PetscInt *findices, *cindices; 8334 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8335 PetscInt foffsets[32], coffsets[32]; 8336 DMPolytopeType ct; 8337 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8338 PetscErrorCode ierr; 8339 8340 PetscFunctionBegin; 8341 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8342 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8343 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8344 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8345 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8346 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8347 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8348 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8349 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8350 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8351 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8352 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8353 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8354 PetscCall(PetscArrayzero(foffsets, 32)); 8355 PetscCall(PetscArrayzero(coffsets, 32)); 8356 /* Column indices */ 8357 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8358 maxFPoints = numCPoints; 8359 /* Compress out points not in the section */ 8360 /* TODO: Squeeze out points with 0 dof as well */ 8361 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8362 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8363 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8364 cpoints[q * 2] = cpoints[p]; 8365 cpoints[q * 2 + 1] = cpoints[p + 1]; 8366 ++q; 8367 } 8368 } 8369 numCPoints = q; 8370 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8371 PetscInt fdof; 8372 8373 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8374 if (!dof) continue; 8375 for (f = 0; f < numFields; ++f) { 8376 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8377 coffsets[f + 1] += fdof; 8378 } 8379 numCIndices += dof; 8380 } 8381 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8382 /* Row indices */ 8383 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8384 { 8385 DMPlexTransform tr; 8386 DMPolytopeType *rct; 8387 PetscInt *rsize, *rcone, *rornt, Nt; 8388 8389 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8390 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8391 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8392 numSubcells = rsize[Nt - 1]; 8393 PetscCall(DMPlexTransformDestroy(&tr)); 8394 } 8395 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8396 for (r = 0, q = 0; r < numSubcells; ++r) { 8397 /* TODO Map from coarse to fine cells */ 8398 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8399 /* Compress out points not in the section */ 8400 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8401 for (p = 0; p < numFPoints * 2; p += 2) { 8402 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8403 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8404 if (!dof) continue; 8405 for (s = 0; s < q; ++s) 8406 if (fpoints[p] == ftotpoints[s * 2]) break; 8407 if (s < q) continue; 8408 ftotpoints[q * 2] = fpoints[p]; 8409 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8410 ++q; 8411 } 8412 } 8413 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8414 } 8415 numFPoints = q; 8416 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8417 PetscInt fdof; 8418 8419 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8420 if (!dof) continue; 8421 for (f = 0; f < numFields; ++f) { 8422 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8423 foffsets[f + 1] += fdof; 8424 } 8425 numFIndices += dof; 8426 } 8427 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8428 8429 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8430 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8431 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8432 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8433 if (numFields) { 8434 const PetscInt **permsF[32] = {NULL}; 8435 const PetscInt **permsC[32] = {NULL}; 8436 8437 for (f = 0; f < numFields; f++) { 8438 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8439 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8440 } 8441 for (p = 0; p < numFPoints; p++) { 8442 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8443 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8444 } 8445 for (p = 0; p < numCPoints; p++) { 8446 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8447 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8448 } 8449 for (f = 0; f < numFields; f++) { 8450 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8451 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8452 } 8453 } else { 8454 const PetscInt **permsF = NULL; 8455 const PetscInt **permsC = NULL; 8456 8457 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8458 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8459 for (p = 0, off = 0; p < numFPoints; p++) { 8460 const PetscInt *perm = permsF ? permsF[p] : NULL; 8461 8462 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8463 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8464 } 8465 for (p = 0, off = 0; p < numCPoints; p++) { 8466 const PetscInt *perm = permsC ? permsC[p] : NULL; 8467 8468 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8469 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8470 } 8471 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8472 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8473 } 8474 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8475 /* TODO: flips */ 8476 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8477 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8478 if (ierr) { 8479 PetscMPIInt rank; 8480 8481 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8482 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8483 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8484 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8485 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8486 } 8487 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8488 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8489 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8490 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8491 PetscFunctionReturn(PETSC_SUCCESS); 8492 } 8493 8494 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8495 { 8496 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8497 PetscInt *cpoints = NULL; 8498 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8499 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8500 DMPolytopeType ct; 8501 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8502 8503 PetscFunctionBegin; 8504 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8505 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8506 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8507 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8508 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8509 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8510 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8511 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8512 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8513 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8514 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8515 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8516 /* Column indices */ 8517 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8518 maxFPoints = numCPoints; 8519 /* Compress out points not in the section */ 8520 /* TODO: Squeeze out points with 0 dof as well */ 8521 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8522 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8523 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8524 cpoints[q * 2] = cpoints[p]; 8525 cpoints[q * 2 + 1] = cpoints[p + 1]; 8526 ++q; 8527 } 8528 } 8529 numCPoints = q; 8530 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8531 PetscInt fdof; 8532 8533 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8534 if (!dof) continue; 8535 for (f = 0; f < numFields; ++f) { 8536 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8537 coffsets[f + 1] += fdof; 8538 } 8539 numCIndices += dof; 8540 } 8541 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8542 /* Row indices */ 8543 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8544 { 8545 DMPlexTransform tr; 8546 DMPolytopeType *rct; 8547 PetscInt *rsize, *rcone, *rornt, Nt; 8548 8549 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8550 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8551 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8552 numSubcells = rsize[Nt - 1]; 8553 PetscCall(DMPlexTransformDestroy(&tr)); 8554 } 8555 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8556 for (r = 0, q = 0; r < numSubcells; ++r) { 8557 /* TODO Map from coarse to fine cells */ 8558 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8559 /* Compress out points not in the section */ 8560 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8561 for (p = 0; p < numFPoints * 2; p += 2) { 8562 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8563 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8564 if (!dof) continue; 8565 for (s = 0; s < q; ++s) 8566 if (fpoints[p] == ftotpoints[s * 2]) break; 8567 if (s < q) continue; 8568 ftotpoints[q * 2] = fpoints[p]; 8569 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8570 ++q; 8571 } 8572 } 8573 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8574 } 8575 numFPoints = q; 8576 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8577 PetscInt fdof; 8578 8579 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8580 if (!dof) continue; 8581 for (f = 0; f < numFields; ++f) { 8582 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8583 foffsets[f + 1] += fdof; 8584 } 8585 numFIndices += dof; 8586 } 8587 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8588 8589 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8590 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8591 if (numFields) { 8592 const PetscInt **permsF[32] = {NULL}; 8593 const PetscInt **permsC[32] = {NULL}; 8594 8595 for (f = 0; f < numFields; f++) { 8596 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8597 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8598 } 8599 for (p = 0; p < numFPoints; p++) { 8600 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8601 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8602 } 8603 for (p = 0; p < numCPoints; p++) { 8604 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8605 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8606 } 8607 for (f = 0; f < numFields; f++) { 8608 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8609 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8610 } 8611 } else { 8612 const PetscInt **permsF = NULL; 8613 const PetscInt **permsC = NULL; 8614 8615 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8616 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8617 for (p = 0, off = 0; p < numFPoints; p++) { 8618 const PetscInt *perm = permsF ? permsF[p] : NULL; 8619 8620 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8621 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8622 } 8623 for (p = 0, off = 0; p < numCPoints; p++) { 8624 const PetscInt *perm = permsC ? permsC[p] : NULL; 8625 8626 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8627 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8628 } 8629 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8630 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8631 } 8632 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8633 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8634 PetscFunctionReturn(PETSC_SUCCESS); 8635 } 8636 8637 /*@ 8638 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8639 8640 Input Parameter: 8641 . dm - The `DMPLEX` object 8642 8643 Output Parameter: 8644 . cellHeight - The height of a cell 8645 8646 Level: developer 8647 8648 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8649 @*/ 8650 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8651 { 8652 DM_Plex *mesh = (DM_Plex *)dm->data; 8653 8654 PetscFunctionBegin; 8655 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8656 PetscAssertPointer(cellHeight, 2); 8657 *cellHeight = mesh->vtkCellHeight; 8658 PetscFunctionReturn(PETSC_SUCCESS); 8659 } 8660 8661 /*@ 8662 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8663 8664 Input Parameters: 8665 + dm - The `DMPLEX` object 8666 - cellHeight - The height of a cell 8667 8668 Level: developer 8669 8670 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8671 @*/ 8672 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8673 { 8674 DM_Plex *mesh = (DM_Plex *)dm->data; 8675 8676 PetscFunctionBegin; 8677 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8678 mesh->vtkCellHeight = cellHeight; 8679 PetscFunctionReturn(PETSC_SUCCESS); 8680 } 8681 8682 /*@ 8683 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8684 8685 Input Parameters: 8686 + dm - The `DMPLEX` object 8687 - ct - The `DMPolytopeType` of the cell 8688 8689 Output Parameters: 8690 + start - The first cell of this type, or `NULL` 8691 - end - The upper bound on this celltype, or `NULL` 8692 8693 Level: advanced 8694 8695 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8696 @*/ 8697 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8698 { 8699 DM_Plex *mesh = (DM_Plex *)dm->data; 8700 DMLabel label; 8701 PetscInt pStart, pEnd; 8702 8703 PetscFunctionBegin; 8704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8705 if (start) { 8706 PetscAssertPointer(start, 3); 8707 *start = 0; 8708 } 8709 if (end) { 8710 PetscAssertPointer(end, 4); 8711 *end = 0; 8712 } 8713 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8714 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8715 if (mesh->tr) { 8716 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8717 } else { 8718 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8719 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8720 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8721 } 8722 PetscFunctionReturn(PETSC_SUCCESS); 8723 } 8724 8725 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8726 { 8727 PetscSection section, globalSection; 8728 PetscInt *numbers, p; 8729 8730 PetscFunctionBegin; 8731 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8732 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8733 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8734 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8735 PetscCall(PetscSectionSetUp(section)); 8736 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8737 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8738 for (p = pStart; p < pEnd; ++p) { 8739 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8740 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8741 else numbers[p - pStart] += shift; 8742 } 8743 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8744 if (globalSize) { 8745 PetscLayout layout; 8746 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8747 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8748 PetscCall(PetscLayoutDestroy(&layout)); 8749 } 8750 PetscCall(PetscSectionDestroy(§ion)); 8751 PetscCall(PetscSectionDestroy(&globalSection)); 8752 PetscFunctionReturn(PETSC_SUCCESS); 8753 } 8754 8755 /*@ 8756 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8757 8758 Input Parameter: 8759 + dm - The `DMPLEX` object 8760 - includeAll - Whether to include all cells, or just the simplex and box cells 8761 8762 Output Parameter: 8763 . globalCellNumbers - Global cell numbers for all cells on this process 8764 8765 Level: developer 8766 8767 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8768 @*/ 8769 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8770 { 8771 PetscInt cellHeight, cStart, cEnd; 8772 8773 PetscFunctionBegin; 8774 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8775 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8776 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8777 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8778 PetscFunctionReturn(PETSC_SUCCESS); 8779 } 8780 8781 /*@ 8782 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8783 8784 Input Parameter: 8785 . dm - The `DMPLEX` object 8786 8787 Output Parameter: 8788 . globalCellNumbers - Global cell numbers for all cells on this process 8789 8790 Level: developer 8791 8792 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8793 @*/ 8794 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8795 { 8796 DM_Plex *mesh = (DM_Plex *)dm->data; 8797 8798 PetscFunctionBegin; 8799 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8800 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8801 *globalCellNumbers = mesh->globalCellNumbers; 8802 PetscFunctionReturn(PETSC_SUCCESS); 8803 } 8804 8805 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8806 { 8807 PetscInt vStart, vEnd; 8808 8809 PetscFunctionBegin; 8810 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8811 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8812 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8813 PetscFunctionReturn(PETSC_SUCCESS); 8814 } 8815 8816 /*@ 8817 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8818 8819 Input Parameter: 8820 . dm - The `DMPLEX` object 8821 8822 Output Parameter: 8823 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8824 8825 Level: developer 8826 8827 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8828 @*/ 8829 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8830 { 8831 DM_Plex *mesh = (DM_Plex *)dm->data; 8832 8833 PetscFunctionBegin; 8834 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8835 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8836 *globalVertexNumbers = mesh->globalVertexNumbers; 8837 PetscFunctionReturn(PETSC_SUCCESS); 8838 } 8839 8840 /*@ 8841 DMPlexCreatePointNumbering - Create a global numbering for all points. 8842 8843 Collective 8844 8845 Input Parameter: 8846 . dm - The `DMPLEX` object 8847 8848 Output Parameter: 8849 . globalPointNumbers - Global numbers for all points on this process 8850 8851 Level: developer 8852 8853 Notes: 8854 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8855 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8856 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8857 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8858 8859 The partitioned mesh is 8860 ``` 8861 (2)--0--(3)--1--(4) (1)--0--(2) 8862 ``` 8863 and its global numbering is 8864 ``` 8865 (3)--0--(4)--1--(5)--2--(6) 8866 ``` 8867 Then the global numbering is provided as 8868 ``` 8869 [0] Number of indices in set 5 8870 [0] 0 0 8871 [0] 1 1 8872 [0] 2 3 8873 [0] 3 4 8874 [0] 4 -6 8875 [1] Number of indices in set 3 8876 [1] 0 2 8877 [1] 1 5 8878 [1] 2 6 8879 ``` 8880 8881 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8882 @*/ 8883 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8884 { 8885 IS nums[4]; 8886 PetscInt depths[4], gdepths[4], starts[4]; 8887 PetscInt depth, d, shift = 0; 8888 PetscBool empty = PETSC_FALSE; 8889 8890 PetscFunctionBegin; 8891 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8892 PetscCall(DMPlexGetDepth(dm, &depth)); 8893 // For unstratified meshes use dim instead of depth 8894 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8895 // If any stratum is empty, we must mark all empty 8896 for (d = 0; d <= depth; ++d) { 8897 PetscInt end; 8898 8899 depths[d] = depth - d; 8900 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8901 if (!(starts[d] - end)) empty = PETSC_TRUE; 8902 } 8903 if (empty) 8904 for (d = 0; d <= depth; ++d) { 8905 depths[d] = -1; 8906 starts[d] = -1; 8907 } 8908 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8909 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8910 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]); 8911 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8912 for (d = 0; d <= depth; ++d) { 8913 PetscInt pStart, pEnd, gsize; 8914 8915 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8916 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8917 shift += gsize; 8918 } 8919 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8920 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8921 PetscFunctionReturn(PETSC_SUCCESS); 8922 } 8923 8924 /*@ 8925 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8926 8927 Collective 8928 8929 Input Parameter: 8930 . dm - The `DMPLEX` object 8931 8932 Output Parameter: 8933 . globalEdgeNumbers - Global numbers for all edges on this process 8934 8935 Level: developer 8936 8937 Notes: 8938 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). In the IS, owned edges will have their non-negative value while edges owned by different ranks will be involuted -(idx+1). 8939 8940 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8941 @*/ 8942 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8943 { 8944 PetscSF sf; 8945 PetscInt eStart, eEnd; 8946 8947 PetscFunctionBegin; 8948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8949 PetscCall(DMGetPointSF(dm, &sf)); 8950 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8951 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8952 PetscFunctionReturn(PETSC_SUCCESS); 8953 } 8954 8955 /*@ 8956 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8957 8958 Input Parameter: 8959 . dm - The `DMPLEX` object 8960 8961 Output Parameter: 8962 . ranks - The rank field 8963 8964 Options Database Key: 8965 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8966 8967 Level: intermediate 8968 8969 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8970 @*/ 8971 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8972 { 8973 DM rdm; 8974 PetscFE fe; 8975 PetscScalar *r; 8976 PetscMPIInt rank; 8977 DMPolytopeType ct; 8978 PetscInt dim, cStart, cEnd, c; 8979 PetscBool simplex; 8980 8981 PetscFunctionBeginUser; 8982 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8983 PetscAssertPointer(ranks, 2); 8984 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8985 PetscCall(DMClone(dm, &rdm)); 8986 PetscCall(DMGetDimension(rdm, &dim)); 8987 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8988 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8989 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8990 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8991 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8992 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8993 PetscCall(PetscFEDestroy(&fe)); 8994 PetscCall(DMCreateDS(rdm)); 8995 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8996 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8997 PetscCall(VecGetArray(*ranks, &r)); 8998 for (c = cStart; c < cEnd; ++c) { 8999 PetscScalar *lr; 9000 9001 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9002 if (lr) *lr = rank; 9003 } 9004 PetscCall(VecRestoreArray(*ranks, &r)); 9005 PetscCall(DMDestroy(&rdm)); 9006 PetscFunctionReturn(PETSC_SUCCESS); 9007 } 9008 9009 /*@ 9010 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9011 9012 Input Parameters: 9013 + dm - The `DMPLEX` 9014 - label - The `DMLabel` 9015 9016 Output Parameter: 9017 . val - The label value field 9018 9019 Options Database Key: 9020 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9021 9022 Level: intermediate 9023 9024 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9025 @*/ 9026 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9027 { 9028 DM rdm, plex; 9029 Vec lval; 9030 PetscSection section; 9031 PetscFE fe; 9032 PetscScalar *v; 9033 PetscInt dim, pStart, pEnd, p, cStart; 9034 DMPolytopeType ct; 9035 char name[PETSC_MAX_PATH_LEN]; 9036 const char *lname, *prefix; 9037 9038 PetscFunctionBeginUser; 9039 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9040 PetscAssertPointer(label, 2); 9041 PetscAssertPointer(val, 3); 9042 PetscCall(DMClone(dm, &rdm)); 9043 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9044 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9045 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9046 PetscCall(DMDestroy(&plex)); 9047 PetscCall(DMGetDimension(rdm, &dim)); 9048 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9049 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9050 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9051 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9052 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9053 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9054 PetscCall(PetscFEDestroy(&fe)); 9055 PetscCall(DMCreateDS(rdm)); 9056 PetscCall(DMCreateGlobalVector(rdm, val)); 9057 PetscCall(DMCreateLocalVector(rdm, &lval)); 9058 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9059 PetscCall(DMGetLocalSection(rdm, §ion)); 9060 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9061 PetscCall(VecGetArray(lval, &v)); 9062 for (p = pStart; p < pEnd; ++p) { 9063 PetscInt cval, dof, off; 9064 9065 PetscCall(PetscSectionGetDof(section, p, &dof)); 9066 if (!dof) continue; 9067 PetscCall(DMLabelGetValue(label, p, &cval)); 9068 PetscCall(PetscSectionGetOffset(section, p, &off)); 9069 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9070 } 9071 PetscCall(VecRestoreArray(lval, &v)); 9072 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9073 PetscCall(VecDestroy(&lval)); 9074 PetscCall(DMDestroy(&rdm)); 9075 PetscFunctionReturn(PETSC_SUCCESS); 9076 } 9077 9078 /*@ 9079 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9080 9081 Input Parameter: 9082 . dm - The `DMPLEX` object 9083 9084 Level: developer 9085 9086 Notes: 9087 This is a useful diagnostic when creating meshes programmatically. 9088 9089 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9090 9091 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9092 @*/ 9093 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9094 { 9095 PetscSection coneSection, supportSection; 9096 const PetscInt *cone, *support; 9097 PetscInt coneSize, c, supportSize, s; 9098 PetscInt pStart, pEnd, p, pp, csize, ssize; 9099 PetscBool storagecheck = PETSC_TRUE; 9100 9101 PetscFunctionBegin; 9102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9103 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9104 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9105 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9106 /* Check that point p is found in the support of its cone points, and vice versa */ 9107 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9108 for (p = pStart; p < pEnd; ++p) { 9109 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9110 PetscCall(DMPlexGetCone(dm, p, &cone)); 9111 for (c = 0; c < coneSize; ++c) { 9112 PetscBool dup = PETSC_FALSE; 9113 PetscInt d; 9114 for (d = c - 1; d >= 0; --d) { 9115 if (cone[c] == cone[d]) { 9116 dup = PETSC_TRUE; 9117 break; 9118 } 9119 } 9120 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9121 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9122 for (s = 0; s < supportSize; ++s) { 9123 if (support[s] == p) break; 9124 } 9125 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9126 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9127 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9128 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9129 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9130 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9131 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9132 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]); 9133 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9134 } 9135 } 9136 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9137 if (p != pp) { 9138 storagecheck = PETSC_FALSE; 9139 continue; 9140 } 9141 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9142 PetscCall(DMPlexGetSupport(dm, p, &support)); 9143 for (s = 0; s < supportSize; ++s) { 9144 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9145 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9146 for (c = 0; c < coneSize; ++c) { 9147 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9148 if (cone[c] != pp) { 9149 c = 0; 9150 break; 9151 } 9152 if (cone[c] == p) break; 9153 } 9154 if (c >= coneSize) { 9155 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9156 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9157 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9158 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9159 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9160 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9161 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9162 } 9163 } 9164 } 9165 if (storagecheck) { 9166 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9167 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9168 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9169 } 9170 PetscFunctionReturn(PETSC_SUCCESS); 9171 } 9172 9173 /* 9174 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. 9175 */ 9176 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9177 { 9178 DMPolytopeType cct; 9179 PetscInt ptpoints[4]; 9180 const PetscInt *cone, *ccone, *ptcone; 9181 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9182 9183 PetscFunctionBegin; 9184 *unsplit = 0; 9185 switch (ct) { 9186 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9187 ptpoints[npt++] = c; 9188 break; 9189 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9190 PetscCall(DMPlexGetCone(dm, c, &cone)); 9191 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9192 for (cp = 0; cp < coneSize; ++cp) { 9193 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9194 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9195 } 9196 break; 9197 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9198 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9199 PetscCall(DMPlexGetCone(dm, c, &cone)); 9200 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9201 for (cp = 0; cp < coneSize; ++cp) { 9202 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9203 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9204 for (ccp = 0; ccp < cconeSize; ++ccp) { 9205 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9206 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9207 PetscInt p; 9208 for (p = 0; p < npt; ++p) 9209 if (ptpoints[p] == ccone[ccp]) break; 9210 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9211 } 9212 } 9213 } 9214 break; 9215 default: 9216 break; 9217 } 9218 for (pt = 0; pt < npt; ++pt) { 9219 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9220 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9221 } 9222 PetscFunctionReturn(PETSC_SUCCESS); 9223 } 9224 9225 /*@ 9226 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9227 9228 Input Parameters: 9229 + dm - The `DMPLEX` object 9230 - cellHeight - Normally 0 9231 9232 Level: developer 9233 9234 Notes: 9235 This is a useful diagnostic when creating meshes programmatically. 9236 Currently applicable only to homogeneous simplex or tensor meshes. 9237 9238 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9239 9240 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9241 @*/ 9242 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9243 { 9244 DMPlexInterpolatedFlag interp; 9245 DMPolytopeType ct; 9246 PetscInt vStart, vEnd, cStart, cEnd, c; 9247 9248 PetscFunctionBegin; 9249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9250 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9251 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9252 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9253 for (c = cStart; c < cEnd; ++c) { 9254 PetscInt *closure = NULL; 9255 PetscInt coneSize, closureSize, cl, Nv = 0; 9256 9257 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9258 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9259 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9260 if (interp == DMPLEX_INTERPOLATED_FULL) { 9261 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9262 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)); 9263 } 9264 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9265 for (cl = 0; cl < closureSize * 2; cl += 2) { 9266 const PetscInt p = closure[cl]; 9267 if ((p >= vStart) && (p < vEnd)) ++Nv; 9268 } 9269 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9270 /* Special Case: Tensor faces with identified vertices */ 9271 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9272 PetscInt unsplit; 9273 9274 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9275 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9276 } 9277 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)); 9278 } 9279 PetscFunctionReturn(PETSC_SUCCESS); 9280 } 9281 9282 /*@ 9283 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9284 9285 Collective 9286 9287 Input Parameters: 9288 + dm - The `DMPLEX` object 9289 - cellHeight - Normally 0 9290 9291 Level: developer 9292 9293 Notes: 9294 This is a useful diagnostic when creating meshes programmatically. 9295 This routine is only relevant for meshes that are fully interpolated across all ranks. 9296 It will error out if a partially interpolated mesh is given on some rank. 9297 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9298 9299 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9300 9301 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9302 @*/ 9303 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9304 { 9305 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9306 DMPlexInterpolatedFlag interpEnum; 9307 9308 PetscFunctionBegin; 9309 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9310 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9311 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9312 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9313 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9314 PetscFunctionReturn(PETSC_SUCCESS); 9315 } 9316 9317 PetscCall(DMGetDimension(dm, &dim)); 9318 PetscCall(DMPlexGetDepth(dm, &depth)); 9319 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9320 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9321 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9322 for (c = cStart; c < cEnd; ++c) { 9323 const PetscInt *cone, *ornt, *faceSizes, *faces; 9324 const DMPolytopeType *faceTypes; 9325 DMPolytopeType ct; 9326 PetscInt numFaces, coneSize, f; 9327 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9328 9329 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9330 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9331 if (unsplit) continue; 9332 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9333 PetscCall(DMPlexGetCone(dm, c, &cone)); 9334 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9335 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9336 for (cl = 0; cl < closureSize * 2; cl += 2) { 9337 const PetscInt p = closure[cl]; 9338 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9339 } 9340 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9341 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); 9342 for (f = 0; f < numFaces; ++f) { 9343 DMPolytopeType fct; 9344 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9345 9346 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9347 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9348 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9349 const PetscInt p = fclosure[cl]; 9350 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9351 } 9352 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]); 9353 for (v = 0; v < fnumCorners; ++v) { 9354 if (fclosure[v] != faces[fOff + v]) { 9355 PetscInt v1; 9356 9357 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9358 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9359 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9360 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9361 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9362 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]); 9363 } 9364 } 9365 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9366 fOff += faceSizes[f]; 9367 } 9368 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9369 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9370 } 9371 } 9372 PetscFunctionReturn(PETSC_SUCCESS); 9373 } 9374 9375 /*@ 9376 DMPlexCheckGeometry - Check the geometry of mesh cells 9377 9378 Input Parameter: 9379 . dm - The `DMPLEX` object 9380 9381 Level: developer 9382 9383 Notes: 9384 This is a useful diagnostic when creating meshes programmatically. 9385 9386 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9387 9388 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9389 @*/ 9390 PetscErrorCode DMPlexCheckGeometry(DM dm) 9391 { 9392 Vec coordinates; 9393 PetscReal detJ, J[9], refVol = 1.0; 9394 PetscReal vol; 9395 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9396 9397 PetscFunctionBegin; 9398 PetscCall(DMGetDimension(dm, &dim)); 9399 PetscCall(DMGetCoordinateDim(dm, &dE)); 9400 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9401 PetscCall(DMPlexGetDepth(dm, &depth)); 9402 for (d = 0; d < dim; ++d) refVol *= 2.0; 9403 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9404 /* Make sure local coordinates are created, because that step is collective */ 9405 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9406 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9407 for (c = cStart; c < cEnd; ++c) { 9408 DMPolytopeType ct; 9409 PetscInt unsplit; 9410 PetscBool ignoreZeroVol = PETSC_FALSE; 9411 9412 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9413 switch (ct) { 9414 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9415 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9416 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9417 ignoreZeroVol = PETSC_TRUE; 9418 break; 9419 default: 9420 break; 9421 } 9422 switch (ct) { 9423 case DM_POLYTOPE_TRI_PRISM: 9424 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9425 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9426 case DM_POLYTOPE_PYRAMID: 9427 continue; 9428 default: 9429 break; 9430 } 9431 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9432 if (unsplit) continue; 9433 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9434 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); 9435 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9436 /* This should work with periodicity since DG coordinates should be used */ 9437 if (depth > 1) { 9438 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9439 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); 9440 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9441 } 9442 } 9443 PetscFunctionReturn(PETSC_SUCCESS); 9444 } 9445 9446 /*@ 9447 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9448 9449 Collective 9450 9451 Input Parameters: 9452 + dm - The `DMPLEX` object 9453 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9454 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9455 9456 Level: developer 9457 9458 Notes: 9459 This is mainly intended for debugging/testing purposes. 9460 9461 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9462 9463 Extra roots can come from periodic cuts, where additional points appear on the boundary 9464 9465 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9466 @*/ 9467 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9468 { 9469 PetscInt l, nleaves, nroots, overlap; 9470 const PetscInt *locals; 9471 const PetscSFNode *remotes; 9472 PetscBool distributed; 9473 MPI_Comm comm; 9474 PetscMPIInt rank; 9475 9476 PetscFunctionBegin; 9477 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9478 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9479 else pointSF = dm->sf; 9480 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9481 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9482 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9483 { 9484 PetscMPIInt mpiFlag; 9485 9486 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9487 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9488 } 9489 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9490 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9491 if (!distributed) { 9492 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); 9493 PetscFunctionReturn(PETSC_SUCCESS); 9494 } 9495 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); 9496 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9497 9498 /* Check SF graph is compatible with DMPlex chart */ 9499 { 9500 PetscInt pStart, pEnd, maxLeaf; 9501 9502 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9503 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9504 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9505 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9506 } 9507 9508 /* Check Point SF has no local points referenced */ 9509 for (l = 0; l < nleaves; l++) { 9510 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); 9511 } 9512 9513 /* Check there are no cells in interface */ 9514 if (!overlap) { 9515 PetscInt cellHeight, cStart, cEnd; 9516 9517 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9518 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9519 for (l = 0; l < nleaves; ++l) { 9520 const PetscInt point = locals ? locals[l] : l; 9521 9522 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9523 } 9524 } 9525 9526 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9527 { 9528 const PetscInt *rootdegree; 9529 9530 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9531 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9532 for (l = 0; l < nleaves; ++l) { 9533 const PetscInt point = locals ? locals[l] : l; 9534 const PetscInt *cone; 9535 PetscInt coneSize, c, idx; 9536 9537 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9538 PetscCall(DMPlexGetCone(dm, point, &cone)); 9539 for (c = 0; c < coneSize; ++c) { 9540 if (!rootdegree[cone[c]]) { 9541 if (locals) { 9542 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9543 } else { 9544 idx = (cone[c] < nleaves) ? cone[c] : -1; 9545 } 9546 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9547 } 9548 } 9549 } 9550 } 9551 PetscFunctionReturn(PETSC_SUCCESS); 9552 } 9553 9554 /*@ 9555 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9556 9557 Collective 9558 9559 Input Parameter: 9560 . dm - The `DMPLEX` object 9561 9562 Level: developer 9563 9564 Notes: 9565 This is mainly intended for debugging/testing purposes. 9566 9567 Other cell types which are disconnected would be caught by the symmetry and face checks. 9568 9569 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9570 9571 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9572 @*/ 9573 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9574 { 9575 PetscInt pStart, pEnd, vStart, vEnd; 9576 9577 PetscFunctionBegin; 9578 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9579 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9580 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9581 for (PetscInt v = vStart; v < vEnd; ++v) { 9582 PetscInt suppSize; 9583 9584 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9585 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9586 } 9587 PetscFunctionReturn(PETSC_SUCCESS); 9588 } 9589 9590 /*@ 9591 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9592 9593 Input Parameter: 9594 . dm - The `DMPLEX` object 9595 9596 Level: developer 9597 9598 Notes: 9599 This is a useful diagnostic when creating meshes programmatically. 9600 9601 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9602 9603 Currently does not include `DMPlexCheckCellShape()`. 9604 9605 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9606 @*/ 9607 PetscErrorCode DMPlexCheck(DM dm) 9608 { 9609 PetscInt cellHeight; 9610 9611 PetscFunctionBegin; 9612 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9613 PetscCall(DMPlexCheckSymmetry(dm)); 9614 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9615 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9616 PetscCall(DMPlexCheckGeometry(dm)); 9617 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9618 PetscCall(DMPlexCheckInterfaceCones(dm)); 9619 PetscCall(DMPlexCheckOrphanVertices(dm)); 9620 PetscFunctionReturn(PETSC_SUCCESS); 9621 } 9622 9623 typedef struct cell_stats { 9624 PetscReal min, max, sum, squaresum; 9625 PetscInt count; 9626 } cell_stats_t; 9627 9628 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9629 { 9630 PetscInt i, N = *len; 9631 9632 for (i = 0; i < N; i++) { 9633 cell_stats_t *A = (cell_stats_t *)a; 9634 cell_stats_t *B = (cell_stats_t *)b; 9635 9636 B->min = PetscMin(A->min, B->min); 9637 B->max = PetscMax(A->max, B->max); 9638 B->sum += A->sum; 9639 B->squaresum += A->squaresum; 9640 B->count += A->count; 9641 } 9642 } 9643 9644 /*@ 9645 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9646 9647 Collective 9648 9649 Input Parameters: 9650 + dm - The `DMPLEX` object 9651 . output - If true, statistics will be displayed on `stdout` 9652 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9653 9654 Level: developer 9655 9656 Notes: 9657 This is mainly intended for debugging/testing purposes. 9658 9659 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9660 9661 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9662 @*/ 9663 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9664 { 9665 DM dmCoarse; 9666 cell_stats_t stats, globalStats; 9667 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9668 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9669 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9670 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9671 PetscMPIInt rank, size; 9672 9673 PetscFunctionBegin; 9674 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9675 stats.min = PETSC_MAX_REAL; 9676 stats.max = PETSC_MIN_REAL; 9677 stats.sum = stats.squaresum = 0.; 9678 stats.count = 0; 9679 9680 PetscCallMPI(MPI_Comm_size(comm, &size)); 9681 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9682 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9683 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9684 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9685 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9686 for (c = cStart; c < cEnd; c++) { 9687 PetscInt i; 9688 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9689 9690 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9691 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9692 for (i = 0; i < PetscSqr(cdim); ++i) { 9693 frobJ += J[i] * J[i]; 9694 frobInvJ += invJ[i] * invJ[i]; 9695 } 9696 cond2 = frobJ * frobInvJ; 9697 cond = PetscSqrtReal(cond2); 9698 9699 stats.min = PetscMin(stats.min, cond); 9700 stats.max = PetscMax(stats.max, cond); 9701 stats.sum += cond; 9702 stats.squaresum += cond2; 9703 stats.count++; 9704 if (output && cond > limit) { 9705 PetscSection coordSection; 9706 Vec coordsLocal; 9707 PetscScalar *coords = NULL; 9708 PetscInt Nv, d, clSize, cl, *closure = NULL; 9709 9710 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9711 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9712 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9713 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9714 for (i = 0; i < Nv / cdim; ++i) { 9715 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9716 for (d = 0; d < cdim; ++d) { 9717 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9718 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9719 } 9720 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9721 } 9722 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9723 for (cl = 0; cl < clSize * 2; cl += 2) { 9724 const PetscInt edge = closure[cl]; 9725 9726 if ((edge >= eStart) && (edge < eEnd)) { 9727 PetscReal len; 9728 9729 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9730 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9731 } 9732 } 9733 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9734 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9735 } 9736 } 9737 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9738 9739 if (size > 1) { 9740 PetscMPIInt blockLengths[2] = {4, 1}; 9741 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9742 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9743 MPI_Op statReduce; 9744 9745 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9746 PetscCallMPI(MPI_Type_commit(&statType)); 9747 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9748 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9749 PetscCallMPI(MPI_Op_free(&statReduce)); 9750 PetscCallMPI(MPI_Type_free(&statType)); 9751 } else { 9752 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9753 } 9754 if (rank == 0) { 9755 count = globalStats.count; 9756 min = globalStats.min; 9757 max = globalStats.max; 9758 mean = globalStats.sum / globalStats.count; 9759 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9760 } 9761 9762 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)); 9763 PetscCall(PetscFree2(J, invJ)); 9764 9765 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9766 if (dmCoarse) { 9767 PetscBool isplex; 9768 9769 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9770 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9771 } 9772 PetscFunctionReturn(PETSC_SUCCESS); 9773 } 9774 9775 /*@ 9776 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9777 orthogonal quality below given tolerance. 9778 9779 Collective 9780 9781 Input Parameters: 9782 + dm - The `DMPLEX` object 9783 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9784 - atol - [0, 1] Absolute tolerance for tagging cells. 9785 9786 Output Parameters: 9787 + OrthQual - `Vec` containing orthogonal quality per cell 9788 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9789 9790 Options Database Keys: 9791 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9792 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9793 9794 Level: intermediate 9795 9796 Notes: 9797 Orthogonal quality is given by the following formula\: 9798 9799 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9800 9801 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 9802 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9803 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9804 calculating the cosine of the angle between these vectors. 9805 9806 Orthogonal quality ranges from 1 (best) to 0 (worst). 9807 9808 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9809 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9810 9811 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9812 9813 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9814 @*/ 9815 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9816 { 9817 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9818 PetscInt *idx; 9819 PetscScalar *oqVals; 9820 const PetscScalar *cellGeomArr, *faceGeomArr; 9821 PetscReal *ci, *fi, *Ai; 9822 MPI_Comm comm; 9823 Vec cellgeom, facegeom; 9824 DM dmFace, dmCell; 9825 IS glob; 9826 ISLocalToGlobalMapping ltog; 9827 PetscViewer vwr; 9828 9829 PetscFunctionBegin; 9830 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9831 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9832 PetscAssertPointer(OrthQual, 4); 9833 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9834 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9835 PetscCall(DMGetDimension(dm, &nc)); 9836 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9837 { 9838 DMPlexInterpolatedFlag interpFlag; 9839 9840 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9841 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9842 PetscMPIInt rank; 9843 9844 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9845 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9846 } 9847 } 9848 if (OrthQualLabel) { 9849 PetscAssertPointer(OrthQualLabel, 5); 9850 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9851 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9852 } else { 9853 *OrthQualLabel = NULL; 9854 } 9855 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9856 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9857 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9858 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9859 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9860 PetscCall(VecCreate(comm, OrthQual)); 9861 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9862 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9863 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9864 PetscCall(VecSetUp(*OrthQual)); 9865 PetscCall(ISDestroy(&glob)); 9866 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9867 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9868 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9869 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9870 PetscCall(VecGetDM(cellgeom, &dmCell)); 9871 PetscCall(VecGetDM(facegeom, &dmFace)); 9872 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9873 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9874 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9875 PetscInt cellarr[2], *adj = NULL; 9876 PetscScalar *cArr, *fArr; 9877 PetscReal minvalc = 1.0, minvalf = 1.0; 9878 PetscFVCellGeom *cg; 9879 9880 idx[cellIter] = cell - cStart; 9881 cellarr[0] = cell; 9882 /* Make indexing into cellGeom easier */ 9883 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9884 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9885 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9886 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9887 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9888 PetscInt i; 9889 const PetscInt neigh = adj[cellneigh]; 9890 PetscReal normci = 0, normfi = 0, normai = 0; 9891 PetscFVCellGeom *cgneigh; 9892 PetscFVFaceGeom *fg; 9893 9894 /* Don't count ourselves in the neighbor list */ 9895 if (neigh == cell) continue; 9896 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9897 cellarr[1] = neigh; 9898 { 9899 PetscInt numcovpts; 9900 const PetscInt *covpts; 9901 9902 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9903 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9904 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9905 } 9906 9907 /* Compute c_i, f_i and their norms */ 9908 for (i = 0; i < nc; i++) { 9909 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9910 fi[i] = fg->centroid[i] - cg->centroid[i]; 9911 Ai[i] = fg->normal[i]; 9912 normci += PetscPowReal(ci[i], 2); 9913 normfi += PetscPowReal(fi[i], 2); 9914 normai += PetscPowReal(Ai[i], 2); 9915 } 9916 normci = PetscSqrtReal(normci); 9917 normfi = PetscSqrtReal(normfi); 9918 normai = PetscSqrtReal(normai); 9919 9920 /* Normalize and compute for each face-cell-normal pair */ 9921 for (i = 0; i < nc; i++) { 9922 ci[i] = ci[i] / normci; 9923 fi[i] = fi[i] / normfi; 9924 Ai[i] = Ai[i] / normai; 9925 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9926 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9927 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9928 } 9929 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9930 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9931 } 9932 PetscCall(PetscFree(adj)); 9933 PetscCall(PetscFree2(cArr, fArr)); 9934 /* Defer to cell if they're equal */ 9935 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9936 if (OrthQualLabel) { 9937 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9938 } 9939 } 9940 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9941 PetscCall(VecAssemblyBegin(*OrthQual)); 9942 PetscCall(VecAssemblyEnd(*OrthQual)); 9943 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9944 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9945 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9946 if (OrthQualLabel) { 9947 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9948 } 9949 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9950 PetscCall(PetscViewerDestroy(&vwr)); 9951 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9952 PetscFunctionReturn(PETSC_SUCCESS); 9953 } 9954 9955 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9956 * interpolator construction */ 9957 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9958 { 9959 PetscSection section, newSection, gsection; 9960 PetscSF sf; 9961 PetscBool hasConstraints, ghasConstraints; 9962 9963 PetscFunctionBegin; 9964 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9965 PetscAssertPointer(odm, 2); 9966 PetscCall(DMGetLocalSection(dm, §ion)); 9967 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9968 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9969 if (!ghasConstraints) { 9970 PetscCall(PetscObjectReference((PetscObject)dm)); 9971 *odm = dm; 9972 PetscFunctionReturn(PETSC_SUCCESS); 9973 } 9974 PetscCall(DMClone(dm, odm)); 9975 PetscCall(DMCopyFields(dm, *odm)); 9976 PetscCall(DMGetLocalSection(*odm, &newSection)); 9977 PetscCall(DMGetPointSF(*odm, &sf)); 9978 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9979 PetscCall(DMSetGlobalSection(*odm, gsection)); 9980 PetscCall(PetscSectionDestroy(&gsection)); 9981 PetscFunctionReturn(PETSC_SUCCESS); 9982 } 9983 9984 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9985 { 9986 DM dmco, dmfo; 9987 Mat interpo; 9988 Vec rscale; 9989 Vec cglobalo, clocal; 9990 Vec fglobal, fglobalo, flocal; 9991 PetscBool regular; 9992 9993 PetscFunctionBegin; 9994 PetscCall(DMGetFullDM(dmc, &dmco)); 9995 PetscCall(DMGetFullDM(dmf, &dmfo)); 9996 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9997 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9998 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9999 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10000 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10001 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10002 PetscCall(VecSet(cglobalo, 0.)); 10003 PetscCall(VecSet(clocal, 0.)); 10004 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10005 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10006 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10007 PetscCall(VecSet(fglobal, 0.)); 10008 PetscCall(VecSet(fglobalo, 0.)); 10009 PetscCall(VecSet(flocal, 0.)); 10010 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10011 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10012 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10013 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10014 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10015 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10016 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10017 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10018 *shift = fglobal; 10019 PetscCall(VecDestroy(&flocal)); 10020 PetscCall(VecDestroy(&fglobalo)); 10021 PetscCall(VecDestroy(&clocal)); 10022 PetscCall(VecDestroy(&cglobalo)); 10023 PetscCall(VecDestroy(&rscale)); 10024 PetscCall(MatDestroy(&interpo)); 10025 PetscCall(DMDestroy(&dmfo)); 10026 PetscCall(DMDestroy(&dmco)); 10027 PetscFunctionReturn(PETSC_SUCCESS); 10028 } 10029 10030 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10031 { 10032 PetscObject shifto; 10033 Vec shift; 10034 10035 PetscFunctionBegin; 10036 if (!interp) { 10037 Vec rscale; 10038 10039 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10040 PetscCall(VecDestroy(&rscale)); 10041 } else { 10042 PetscCall(PetscObjectReference((PetscObject)interp)); 10043 } 10044 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10045 if (!shifto) { 10046 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10047 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10048 shifto = (PetscObject)shift; 10049 PetscCall(VecDestroy(&shift)); 10050 } 10051 shift = (Vec)shifto; 10052 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10053 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10054 PetscCall(MatDestroy(&interp)); 10055 PetscFunctionReturn(PETSC_SUCCESS); 10056 } 10057 10058 /* Pointwise interpolation 10059 Just code FEM for now 10060 u^f = I u^c 10061 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10062 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10063 I_{ij} = psi^f_i phi^c_j 10064 */ 10065 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10066 { 10067 PetscSection gsc, gsf; 10068 PetscInt m, n; 10069 void *ctx; 10070 DM cdm; 10071 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10072 10073 PetscFunctionBegin; 10074 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10075 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10076 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10077 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10078 10079 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10080 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10081 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10082 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10083 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10084 10085 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10086 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10087 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10088 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10089 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10090 if (scaling) { 10091 /* Use naive scaling */ 10092 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10093 } 10094 PetscFunctionReturn(PETSC_SUCCESS); 10095 } 10096 10097 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10098 { 10099 VecScatter ctx; 10100 10101 PetscFunctionBegin; 10102 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10103 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10104 PetscCall(VecScatterDestroy(&ctx)); 10105 PetscFunctionReturn(PETSC_SUCCESS); 10106 } 10107 10108 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[]) 10109 { 10110 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10111 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10112 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10113 } 10114 10115 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 10116 { 10117 DM dmc; 10118 PetscDS ds; 10119 Vec ones, locmass; 10120 IS cellIS; 10121 PetscFormKey key; 10122 PetscInt depth; 10123 10124 PetscFunctionBegin; 10125 PetscCall(DMClone(dm, &dmc)); 10126 PetscCall(DMCopyDisc(dm, dmc)); 10127 PetscCall(DMGetDS(dmc, &ds)); 10128 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10129 PetscCall(DMCreateGlobalVector(dmc, mass)); 10130 PetscCall(DMGetLocalVector(dmc, &ones)); 10131 PetscCall(DMGetLocalVector(dmc, &locmass)); 10132 PetscCall(DMPlexGetDepth(dmc, &depth)); 10133 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10134 PetscCall(VecSet(locmass, 0.0)); 10135 PetscCall(VecSet(ones, 1.0)); 10136 key.label = NULL; 10137 key.value = 0; 10138 key.field = 0; 10139 key.part = 0; 10140 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10141 PetscCall(ISDestroy(&cellIS)); 10142 PetscCall(VecSet(*mass, 0.0)); 10143 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 10144 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 10145 PetscCall(DMRestoreLocalVector(dmc, &ones)); 10146 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 10147 PetscCall(DMDestroy(&dmc)); 10148 PetscFunctionReturn(PETSC_SUCCESS); 10149 } 10150 10151 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10152 { 10153 PetscSection gsc, gsf; 10154 PetscInt m, n; 10155 void *ctx; 10156 DM cdm; 10157 PetscBool regular; 10158 10159 PetscFunctionBegin; 10160 if (dmFine == dmCoarse) { 10161 DM dmc; 10162 PetscDS ds; 10163 PetscWeakForm wf; 10164 Vec u; 10165 IS cellIS; 10166 PetscFormKey key; 10167 PetscInt depth; 10168 10169 PetscCall(DMClone(dmFine, &dmc)); 10170 PetscCall(DMCopyDisc(dmFine, dmc)); 10171 PetscCall(DMGetDS(dmc, &ds)); 10172 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10173 PetscCall(PetscWeakFormClear(wf)); 10174 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10175 PetscCall(DMCreateMatrix(dmc, mass)); 10176 PetscCall(DMGetLocalVector(dmc, &u)); 10177 PetscCall(DMPlexGetDepth(dmc, &depth)); 10178 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10179 PetscCall(MatZeroEntries(*mass)); 10180 key.label = NULL; 10181 key.value = 0; 10182 key.field = 0; 10183 key.part = 0; 10184 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10185 PetscCall(ISDestroy(&cellIS)); 10186 PetscCall(DMRestoreLocalVector(dmc, &u)); 10187 PetscCall(DMDestroy(&dmc)); 10188 } else { 10189 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10190 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10191 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10192 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10193 10194 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10195 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10196 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10197 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10198 10199 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10200 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10201 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10202 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10203 } 10204 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10205 PetscFunctionReturn(PETSC_SUCCESS); 10206 } 10207 10208 /*@ 10209 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10210 10211 Input Parameter: 10212 . dm - The `DMPLEX` object 10213 10214 Output Parameter: 10215 . regular - The flag 10216 10217 Level: intermediate 10218 10219 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10220 @*/ 10221 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10222 { 10223 PetscFunctionBegin; 10224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10225 PetscAssertPointer(regular, 2); 10226 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10227 PetscFunctionReturn(PETSC_SUCCESS); 10228 } 10229 10230 /*@ 10231 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10232 10233 Input Parameters: 10234 + dm - The `DMPLEX` object 10235 - regular - The flag 10236 10237 Level: intermediate 10238 10239 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10240 @*/ 10241 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10242 { 10243 PetscFunctionBegin; 10244 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10245 ((DM_Plex *)dm->data)->regularRefinement = regular; 10246 PetscFunctionReturn(PETSC_SUCCESS); 10247 } 10248 10249 /*@ 10250 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10251 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10252 10253 Not Collective 10254 10255 Input Parameter: 10256 . dm - The `DMPLEX` object 10257 10258 Output Parameters: 10259 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10260 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10261 10262 Level: intermediate 10263 10264 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10265 @*/ 10266 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10267 { 10268 DM_Plex *plex = (DM_Plex *)dm->data; 10269 10270 PetscFunctionBegin; 10271 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10272 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10273 if (anchorSection) *anchorSection = plex->anchorSection; 10274 if (anchorIS) *anchorIS = plex->anchorIS; 10275 PetscFunctionReturn(PETSC_SUCCESS); 10276 } 10277 10278 /*@ 10279 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10280 10281 Collective 10282 10283 Input Parameters: 10284 + dm - The `DMPLEX` object 10285 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10286 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10287 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10288 10289 Level: intermediate 10290 10291 Notes: 10292 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10293 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10294 combination of other points' degrees of freedom. 10295 10296 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10297 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10298 10299 The reference counts of `anchorSection` and `anchorIS` are incremented. 10300 10301 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10302 @*/ 10303 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10304 { 10305 DM_Plex *plex = (DM_Plex *)dm->data; 10306 PetscMPIInt result; 10307 10308 PetscFunctionBegin; 10309 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10310 if (anchorSection) { 10311 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10312 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10313 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10314 } 10315 if (anchorIS) { 10316 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10317 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10318 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10319 } 10320 10321 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10322 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10323 plex->anchorSection = anchorSection; 10324 10325 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10326 PetscCall(ISDestroy(&plex->anchorIS)); 10327 plex->anchorIS = anchorIS; 10328 10329 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10330 PetscInt size, a, pStart, pEnd; 10331 const PetscInt *anchors; 10332 10333 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10334 PetscCall(ISGetLocalSize(anchorIS, &size)); 10335 PetscCall(ISGetIndices(anchorIS, &anchors)); 10336 for (a = 0; a < size; a++) { 10337 PetscInt p; 10338 10339 p = anchors[a]; 10340 if (p >= pStart && p < pEnd) { 10341 PetscInt dof; 10342 10343 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10344 if (dof) { 10345 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10346 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10347 } 10348 } 10349 } 10350 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10351 } 10352 /* reset the generic constraints */ 10353 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10354 PetscFunctionReturn(PETSC_SUCCESS); 10355 } 10356 10357 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10358 { 10359 PetscSection anchorSection; 10360 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10361 10362 PetscFunctionBegin; 10363 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10364 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10365 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10366 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10367 if (numFields) { 10368 PetscInt f; 10369 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10370 10371 for (f = 0; f < numFields; f++) { 10372 PetscInt numComp; 10373 10374 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10375 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10376 } 10377 } 10378 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10379 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10380 pStart = PetscMax(pStart, sStart); 10381 pEnd = PetscMin(pEnd, sEnd); 10382 pEnd = PetscMax(pStart, pEnd); 10383 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10384 for (p = pStart; p < pEnd; p++) { 10385 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10386 if (dof) { 10387 PetscCall(PetscSectionGetDof(section, p, &dof)); 10388 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10389 for (f = 0; f < numFields; f++) { 10390 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10391 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10392 } 10393 } 10394 } 10395 PetscCall(PetscSectionSetUp(*cSec)); 10396 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10397 PetscFunctionReturn(PETSC_SUCCESS); 10398 } 10399 10400 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10401 { 10402 PetscSection aSec; 10403 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10404 const PetscInt *anchors; 10405 PetscInt numFields, f; 10406 IS aIS; 10407 MatType mtype; 10408 PetscBool iscuda, iskokkos; 10409 10410 PetscFunctionBegin; 10411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10412 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10413 PetscCall(PetscSectionGetStorageSize(section, &n)); 10414 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10415 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10416 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10417 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10418 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10419 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10420 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10421 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10422 else mtype = MATSEQAIJ; 10423 PetscCall(MatSetType(*cMat, mtype)); 10424 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10425 PetscCall(ISGetIndices(aIS, &anchors)); 10426 /* cSec will be a subset of aSec and section */ 10427 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10428 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10429 PetscCall(PetscMalloc1(m + 1, &i)); 10430 i[0] = 0; 10431 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10432 for (p = pStart; p < pEnd; p++) { 10433 PetscInt rDof, rOff, r; 10434 10435 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10436 if (!rDof) continue; 10437 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10438 if (numFields) { 10439 for (f = 0; f < numFields; f++) { 10440 annz = 0; 10441 for (r = 0; r < rDof; r++) { 10442 a = anchors[rOff + r]; 10443 if (a < sStart || a >= sEnd) continue; 10444 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10445 annz += aDof; 10446 } 10447 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10448 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10449 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10450 } 10451 } else { 10452 annz = 0; 10453 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10454 for (q = 0; q < dof; q++) { 10455 a = anchors[rOff + q]; 10456 if (a < sStart || a >= sEnd) continue; 10457 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10458 annz += aDof; 10459 } 10460 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10461 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10462 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10463 } 10464 } 10465 nnz = i[m]; 10466 PetscCall(PetscMalloc1(nnz, &j)); 10467 offset = 0; 10468 for (p = pStart; p < pEnd; p++) { 10469 if (numFields) { 10470 for (f = 0; f < numFields; f++) { 10471 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10472 for (q = 0; q < dof; q++) { 10473 PetscInt rDof, rOff, r; 10474 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10475 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10476 for (r = 0; r < rDof; r++) { 10477 PetscInt s; 10478 10479 a = anchors[rOff + r]; 10480 if (a < sStart || a >= sEnd) continue; 10481 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10482 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10483 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10484 } 10485 } 10486 } 10487 } else { 10488 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10489 for (q = 0; q < dof; q++) { 10490 PetscInt rDof, rOff, r; 10491 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10492 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10493 for (r = 0; r < rDof; r++) { 10494 PetscInt s; 10495 10496 a = anchors[rOff + r]; 10497 if (a < sStart || a >= sEnd) continue; 10498 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10499 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10500 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10501 } 10502 } 10503 } 10504 } 10505 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10506 PetscCall(PetscFree(i)); 10507 PetscCall(PetscFree(j)); 10508 PetscCall(ISRestoreIndices(aIS, &anchors)); 10509 PetscFunctionReturn(PETSC_SUCCESS); 10510 } 10511 10512 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10513 { 10514 DM_Plex *plex = (DM_Plex *)dm->data; 10515 PetscSection anchorSection, section, cSec; 10516 Mat cMat; 10517 10518 PetscFunctionBegin; 10519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10520 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10521 if (anchorSection) { 10522 PetscInt Nf; 10523 10524 PetscCall(DMGetLocalSection(dm, §ion)); 10525 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10526 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10527 PetscCall(DMGetNumFields(dm, &Nf)); 10528 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10529 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10530 PetscCall(PetscSectionDestroy(&cSec)); 10531 PetscCall(MatDestroy(&cMat)); 10532 } 10533 PetscFunctionReturn(PETSC_SUCCESS); 10534 } 10535 10536 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10537 { 10538 IS subis; 10539 PetscSection section, subsection; 10540 10541 PetscFunctionBegin; 10542 PetscCall(DMGetLocalSection(dm, §ion)); 10543 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10544 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10545 /* Create subdomain */ 10546 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10547 /* Create submodel */ 10548 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10549 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10550 PetscCall(DMSetLocalSection(*subdm, subsection)); 10551 PetscCall(PetscSectionDestroy(&subsection)); 10552 PetscCall(DMCopyDisc(dm, *subdm)); 10553 /* Create map from submodel to global model */ 10554 if (is) { 10555 PetscSection sectionGlobal, subsectionGlobal; 10556 IS spIS; 10557 const PetscInt *spmap; 10558 PetscInt *subIndices; 10559 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10560 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10561 10562 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10563 PetscCall(ISGetIndices(spIS, &spmap)); 10564 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10565 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10566 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10567 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10568 for (p = pStart; p < pEnd; ++p) { 10569 PetscInt gdof, pSubSize = 0; 10570 10571 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10572 if (gdof > 0) { 10573 for (f = 0; f < Nf; ++f) { 10574 PetscInt fdof, fcdof; 10575 10576 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10577 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10578 pSubSize += fdof - fcdof; 10579 } 10580 subSize += pSubSize; 10581 if (pSubSize) { 10582 if (bs < 0) { 10583 bs = pSubSize; 10584 } else if (bs != pSubSize) { 10585 /* Layout does not admit a pointwise block size */ 10586 bs = 1; 10587 } 10588 } 10589 } 10590 } 10591 /* Must have same blocksize on all procs (some might have no points) */ 10592 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10593 bsLocal[1] = bs; 10594 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10595 if (bsMinMax[0] != bsMinMax[1]) { 10596 bs = 1; 10597 } else { 10598 bs = bsMinMax[0]; 10599 } 10600 PetscCall(PetscMalloc1(subSize, &subIndices)); 10601 for (p = pStart; p < pEnd; ++p) { 10602 PetscInt gdof, goff; 10603 10604 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10605 if (gdof > 0) { 10606 const PetscInt point = spmap[p]; 10607 10608 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10609 for (f = 0; f < Nf; ++f) { 10610 PetscInt fdof, fcdof, fc, f2, poff = 0; 10611 10612 /* Can get rid of this loop by storing field information in the global section */ 10613 for (f2 = 0; f2 < f; ++f2) { 10614 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10615 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10616 poff += fdof - fcdof; 10617 } 10618 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10619 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10620 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10621 } 10622 } 10623 } 10624 PetscCall(ISRestoreIndices(spIS, &spmap)); 10625 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10626 if (bs > 1) { 10627 /* We need to check that the block size does not come from non-contiguous fields */ 10628 PetscInt i, j, set = 1; 10629 for (i = 0; i < subSize; i += bs) { 10630 for (j = 0; j < bs; ++j) { 10631 if (subIndices[i + j] != subIndices[i] + j) { 10632 set = 0; 10633 break; 10634 } 10635 } 10636 } 10637 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10638 } 10639 /* Attach nullspace */ 10640 for (f = 0; f < Nf; ++f) { 10641 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10642 if ((*subdm)->nullspaceConstructors[f]) break; 10643 } 10644 if (f < Nf) { 10645 MatNullSpace nullSpace; 10646 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10647 10648 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10649 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10650 } 10651 } 10652 PetscFunctionReturn(PETSC_SUCCESS); 10653 } 10654 10655 /*@ 10656 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10657 10658 Input Parameters: 10659 + dm - The `DM` 10660 - dummy - unused argument 10661 10662 Options Database Key: 10663 . -dm_plex_monitor_throughput - Activate the monitor 10664 10665 Level: developer 10666 10667 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10668 @*/ 10669 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10670 { 10671 PetscLogHandler default_handler; 10672 10673 PetscFunctionBegin; 10674 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10675 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10676 if (default_handler) { 10677 PetscLogEvent event; 10678 PetscEventPerfInfo eventInfo; 10679 PetscReal cellRate, flopRate; 10680 PetscInt cStart, cEnd, Nf, N; 10681 const char *name; 10682 10683 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10684 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10685 PetscCall(DMGetNumFields(dm, &Nf)); 10686 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10687 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10688 N = (cEnd - cStart) * Nf * eventInfo.count; 10689 flopRate = eventInfo.flops / eventInfo.time; 10690 cellRate = N / eventInfo.time; 10691 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))); 10692 } else { 10693 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."); 10694 } 10695 PetscFunctionReturn(PETSC_SUCCESS); 10696 } 10697