1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 89 90 PetscFunctionBegin; 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 93 PetscCall(ISGetLocalSize(valueIS, &Nct)); 94 PetscCall(ISGetIndices(valueIS, &ctypes)); 95 if (!Nct) cS = cE = 0; 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 } 114 PetscCall(ISDestroy(&valueIS)); 115 // Reset label for fast lookup 116 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 117 if (cStart) *cStart = cS; 118 if (cEnd) *cEnd = cE; 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 123 { 124 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 125 PetscInt *sStart, *sEnd; 126 PetscViewerVTKFieldType *ft; 127 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 128 DMLabel depthLabel, ctLabel; 129 130 PetscFunctionBegin; 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 } 162 163 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 164 *types = 0; 165 166 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 167 if (globalvcdof[c]) ++(*types); 168 } 169 170 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 171 t = 0; 172 if (globalvcdof[DM_NUM_POLYTOPES]) { 173 sStart[t] = vStart; 174 sEnd[t] = vEnd; 175 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 176 ++t; 177 } 178 179 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 180 if (globalvcdof[c]) { 181 const DMPolytopeType ict = (DMPolytopeType)c; 182 183 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 184 sStart[t] = cStart; 185 sEnd[t] = cEnd; 186 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 187 ++t; 188 } 189 } 190 191 if (!*types) { 192 if (field >= 0) { 193 const char *fieldname; 194 195 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 196 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 197 } else { 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 199 } 200 } 201 202 *ssStart = sStart; 203 *ssEnd = sEnd; 204 *sft = ft; 205 PetscFunctionReturn(PETSC_SUCCESS); 206 } 207 208 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 209 { 210 PetscFunctionBegin; 211 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 216 { 217 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 218 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 219 220 PetscFunctionBegin; 221 *ft = PETSC_VTK_INVALID; 222 PetscCall(DMGetCoordinateDim(dm, &cdim)); 223 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 224 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 225 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 226 if (field >= 0) { 227 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 228 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 229 } else { 230 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 231 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 232 } 233 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 234 if (globalvcdof[0]) { 235 *sStart = vStart; 236 *sEnd = vEnd; 237 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 238 else *ft = PETSC_VTK_POINT_FIELD; 239 } else if (globalvcdof[1]) { 240 *sStart = cStart; 241 *sEnd = cEnd; 242 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 243 else *ft = PETSC_VTK_CELL_FIELD; 244 } else { 245 if (field >= 0) { 246 const char *fieldname; 247 248 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 249 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 250 } else { 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 252 } 253 } 254 PetscFunctionReturn(PETSC_SUCCESS); 255 } 256 257 /*@ 258 DMPlexVecView1D - Plot many 1D solutions on the same line graph 259 260 Collective 261 262 Input Parameters: 263 + dm - The `DMPLEX` object 264 . n - The number of vectors 265 . u - The array of local vectors 266 - viewer - The `PetscViewer` 267 268 Level: advanced 269 270 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 271 @*/ 272 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 273 { 274 PetscDS ds; 275 PetscDraw draw = NULL; 276 PetscDrawLG lg; 277 Vec coordinates; 278 const PetscScalar *coords, **sol; 279 PetscReal *vals; 280 PetscInt *Nc; 281 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 282 char **names; 283 284 PetscFunctionBegin; 285 PetscCall(DMGetDS(dm, &ds)); 286 PetscCall(PetscDSGetNumFields(ds, &Nf)); 287 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 288 PetscCall(PetscDSGetComponents(ds, &Nc)); 289 290 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 291 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 292 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 293 294 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 295 for (i = 0, l = 0; i < n; ++i) { 296 const char *vname; 297 298 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 299 for (f = 0; f < Nf; ++f) { 300 PetscObject disc; 301 const char *fname; 302 char tmpname[PETSC_MAX_PATH_LEN]; 303 304 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 305 /* TODO Create names for components */ 306 for (c = 0; c < Nc[f]; ++c, ++l) { 307 PetscCall(PetscObjectGetName(disc, &fname)); 308 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 309 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 311 PetscCall(PetscStrallocpy(tmpname, &names[l])); 312 } 313 } 314 } 315 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 316 /* Just add P_1 support for now */ 317 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 318 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 319 PetscCall(VecGetArrayRead(coordinates, &coords)); 320 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 321 for (v = vStart; v < vEnd; ++v) { 322 PetscScalar *x, *svals; 323 324 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 325 for (i = 0; i < n; ++i) { 326 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 327 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 328 } 329 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 330 } 331 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 332 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 333 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 334 PetscCall(PetscFree3(sol, names, vals)); 335 336 PetscCall(PetscDrawLGDraw(lg)); 337 PetscCall(PetscDrawLGDestroy(&lg)); 338 PetscFunctionReturn(PETSC_SUCCESS); 339 } 340 341 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 342 { 343 DM dm; 344 345 PetscFunctionBegin; 346 PetscCall(VecGetDM(u, &dm)); 347 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 348 PetscFunctionReturn(PETSC_SUCCESS); 349 } 350 351 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 352 { 353 DM dm; 354 PetscSection s; 355 PetscDraw draw, popup; 356 DM cdm; 357 PetscSection coordSection; 358 Vec coordinates; 359 const PetscScalar *array; 360 PetscReal lbound[3], ubound[3]; 361 PetscReal vbound[2], time; 362 PetscBool flg; 363 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 364 const char *name; 365 char title[PETSC_MAX_PATH_LEN]; 366 367 PetscFunctionBegin; 368 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 369 PetscCall(VecGetDM(v, &dm)); 370 PetscCall(DMGetCoordinateDim(dm, &dim)); 371 PetscCall(DMGetLocalSection(dm, &s)); 372 PetscCall(PetscSectionGetNumFields(s, &Nf)); 373 PetscCall(DMGetCoarsenLevel(dm, &level)); 374 PetscCall(DMGetCoordinateDM(dm, &cdm)); 375 PetscCall(DMGetLocalSection(cdm, &coordSection)); 376 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 377 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 378 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 379 380 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 381 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 382 383 PetscCall(VecGetLocalSize(coordinates, &N)); 384 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 385 PetscCall(PetscDrawClear(draw)); 386 387 /* Could implement something like DMDASelectFields() */ 388 for (f = 0; f < Nf; ++f) { 389 DM fdm = dm; 390 Vec fv = v; 391 IS fis; 392 char prefix[PETSC_MAX_PATH_LEN]; 393 const char *fname; 394 395 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 396 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 397 398 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 399 else prefix[0] = '\0'; 400 if (Nf > 1) { 401 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 402 PetscCall(VecGetSubVector(v, fis, &fv)); 403 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 404 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 405 } 406 for (comp = 0; comp < Nc; ++comp, ++w) { 407 PetscInt nmax = 2; 408 409 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 410 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 411 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 412 PetscCall(PetscDrawSetTitle(draw, title)); 413 414 /* TODO Get max and min only for this component */ 415 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 416 if (!flg) { 417 PetscCall(VecMin(fv, NULL, &vbound[0])); 418 PetscCall(VecMax(fv, NULL, &vbound[1])); 419 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 420 } 421 422 PetscCall(PetscDrawGetPopup(draw, &popup)); 423 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 424 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 425 PetscCall(VecGetArrayRead(fv, &array)); 426 for (c = cStart; c < cEnd; ++c) { 427 PetscScalar *coords = NULL, *a = NULL; 428 const PetscScalar *coords_arr; 429 PetscBool isDG; 430 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 431 432 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 433 if (a) { 434 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 435 color[1] = color[2] = color[3] = color[0]; 436 } else { 437 PetscScalar *vals = NULL; 438 PetscInt numVals, va; 439 440 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 441 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 442 switch (numVals / Nc) { 443 case 3: /* P1 Triangle */ 444 case 4: /* P1 Quadrangle */ 445 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 446 break; 447 case 6: /* P2 Triangle */ 448 case 8: /* P2 Quadrangle */ 449 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 450 break; 451 default: 452 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 453 } 454 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 455 } 456 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 457 switch (numCoords) { 458 case 6: 459 case 12: /* Localized triangle */ 460 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 461 break; 462 case 8: 463 case 16: /* Localized quadrilateral */ 464 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 465 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 466 break; 467 default: 468 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 469 } 470 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 471 } 472 PetscCall(VecRestoreArrayRead(fv, &array)); 473 PetscCall(PetscDrawFlush(draw)); 474 PetscCall(PetscDrawPause(draw)); 475 PetscCall(PetscDrawSave(draw)); 476 } 477 if (Nf > 1) { 478 PetscCall(VecRestoreSubVector(v, fis, &fv)); 479 PetscCall(ISDestroy(&fis)); 480 PetscCall(DMDestroy(&fdm)); 481 } 482 } 483 PetscFunctionReturn(PETSC_SUCCESS); 484 } 485 486 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 487 { 488 DM dm; 489 PetscDraw draw; 490 PetscInt dim; 491 PetscBool isnull; 492 493 PetscFunctionBegin; 494 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 495 PetscCall(PetscDrawIsNull(draw, &isnull)); 496 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 497 498 PetscCall(VecGetDM(v, &dm)); 499 PetscCall(DMGetCoordinateDim(dm, &dim)); 500 switch (dim) { 501 case 1: 502 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 503 break; 504 case 2: 505 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 506 break; 507 default: 508 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 509 } 510 PetscFunctionReturn(PETSC_SUCCESS); 511 } 512 513 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 514 { 515 DM dm; 516 Vec locv; 517 const char *name; 518 PetscSection section; 519 PetscInt pStart, pEnd; 520 PetscInt numFields; 521 PetscViewerVTKFieldType ft; 522 523 PetscFunctionBegin; 524 PetscCall(VecGetDM(v, &dm)); 525 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 526 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 527 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 528 PetscCall(VecCopy(v, locv)); 529 PetscCall(DMGetLocalSection(dm, §ion)); 530 PetscCall(PetscSectionGetNumFields(section, &numFields)); 531 if (!numFields) { 532 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 533 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 534 } else { 535 PetscInt f; 536 537 for (f = 0; f < numFields; f++) { 538 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 539 if (ft == PETSC_VTK_INVALID) continue; 540 PetscCall(PetscObjectReference((PetscObject)locv)); 541 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 542 } 543 PetscCall(VecDestroy(&locv)); 544 } 545 PetscFunctionReturn(PETSC_SUCCESS); 546 } 547 548 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 549 { 550 DM dm; 551 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 552 553 PetscFunctionBegin; 554 PetscCall(VecGetDM(v, &dm)); 555 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 561 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 562 PetscInt i, numFields; 563 PetscObject fe; 564 PetscBool fem = PETSC_FALSE; 565 Vec locv = v; 566 const char *name; 567 PetscInt step; 568 PetscReal time; 569 570 PetscCall(DMGetNumFields(dm, &numFields)); 571 for (i = 0; i < numFields; i++) { 572 PetscCall(DMGetField(dm, i, NULL, &fe)); 573 if (fe->classid == PETSCFE_CLASSID) { 574 fem = PETSC_TRUE; 575 break; 576 } 577 } 578 if (fem) { 579 PetscObject isZero; 580 581 PetscCall(DMGetLocalVector(dm, &locv)); 582 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 583 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 584 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 585 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 586 PetscCall(VecCopy(v, locv)); 587 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 588 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 589 } 590 if (isvtk) { 591 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 592 } else if (ishdf5) { 593 #if defined(PETSC_HAVE_HDF5) 594 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 595 #else 596 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 597 #endif 598 } else if (isdraw) { 599 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 600 } else if (isglvis) { 601 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 602 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 603 PetscCall(VecView_GLVis(locv, viewer)); 604 } else if (iscgns) { 605 #if defined(PETSC_HAVE_CGNS) 606 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 607 #else 608 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 609 #endif 610 } 611 if (fem) { 612 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 613 PetscCall(DMRestoreLocalVector(dm, &locv)); 614 } 615 } else { 616 PetscBool isseq; 617 618 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 619 if (isseq) PetscCall(VecView_Seq(v, viewer)); 620 else PetscCall(VecView_MPI(v, viewer)); 621 } 622 PetscFunctionReturn(PETSC_SUCCESS); 623 } 624 625 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 626 { 627 DM dm; 628 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 629 630 PetscFunctionBegin; 631 PetscCall(VecGetDM(v, &dm)); 632 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 633 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 639 if (isvtk || isdraw || isglvis || iscgns) { 640 Vec locv; 641 PetscObject isZero; 642 const char *name; 643 644 PetscCall(DMGetLocalVector(dm, &locv)); 645 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 646 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 647 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 648 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 649 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 650 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 651 PetscCall(VecView_Plex_Local(locv, viewer)); 652 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 653 PetscCall(DMRestoreLocalVector(dm, &locv)); 654 } else if (ishdf5) { 655 #if defined(PETSC_HAVE_HDF5) 656 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 657 #else 658 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 659 #endif 660 } else if (isexodusii) { 661 #if defined(PETSC_HAVE_EXODUSII) 662 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 663 #else 664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 665 #endif 666 } else { 667 PetscBool isseq; 668 669 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 670 if (isseq) PetscCall(VecView_Seq(v, viewer)); 671 else PetscCall(VecView_MPI(v, viewer)); 672 } 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 677 { 678 DM dm; 679 MPI_Comm comm; 680 PetscViewerFormat format; 681 Vec v; 682 PetscBool isvtk, ishdf5; 683 684 PetscFunctionBegin; 685 PetscCall(VecGetDM(originalv, &dm)); 686 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 687 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 688 PetscCall(PetscViewerGetFormat(viewer, &format)); 689 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 691 if (format == PETSC_VIEWER_NATIVE) { 692 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 693 /* this need a better fix */ 694 if (dm->useNatural) { 695 if (dm->sfNatural) { 696 const char *vecname; 697 PetscInt n, nroots; 698 699 PetscCall(VecGetLocalSize(originalv, &n)); 700 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 701 if (n == nroots) { 702 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 703 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 704 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 705 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 706 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 707 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 709 } else v = originalv; 710 } else v = originalv; 711 712 if (ishdf5) { 713 #if defined(PETSC_HAVE_HDF5) 714 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 715 #else 716 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 717 #endif 718 } else if (isvtk) { 719 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 720 } else { 721 PetscBool isseq; 722 723 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 724 if (isseq) PetscCall(VecView_Seq(v, viewer)); 725 else PetscCall(VecView_MPI(v, viewer)); 726 } 727 if (v != originalv) PetscCall(VecDestroy(&v)); 728 PetscFunctionReturn(PETSC_SUCCESS); 729 } 730 731 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 732 { 733 DM dm; 734 PetscBool ishdf5; 735 736 PetscFunctionBegin; 737 PetscCall(VecGetDM(v, &dm)); 738 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 739 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 740 if (ishdf5) { 741 DM dmBC; 742 Vec gv; 743 const char *name; 744 745 PetscCall(DMGetOutputDM(dm, &dmBC)); 746 PetscCall(DMGetGlobalVector(dmBC, &gv)); 747 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 748 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 749 PetscCall(VecLoad_Default(gv, viewer)); 750 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 751 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 753 } else PetscCall(VecLoad_Default(v, viewer)); 754 PetscFunctionReturn(PETSC_SUCCESS); 755 } 756 757 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 758 { 759 DM dm; 760 PetscBool ishdf5, isexodusii; 761 762 PetscFunctionBegin; 763 PetscCall(VecGetDM(v, &dm)); 764 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 765 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 767 if (ishdf5) { 768 #if defined(PETSC_HAVE_HDF5) 769 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 770 #else 771 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 772 #endif 773 } else if (isexodusii) { 774 #if defined(PETSC_HAVE_EXODUSII) 775 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 776 #else 777 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 778 #endif 779 } else PetscCall(VecLoad_Default(v, viewer)); 780 PetscFunctionReturn(PETSC_SUCCESS); 781 } 782 783 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 784 { 785 DM dm; 786 PetscViewerFormat format; 787 PetscBool ishdf5; 788 789 PetscFunctionBegin; 790 PetscCall(VecGetDM(originalv, &dm)); 791 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 792 PetscCall(PetscViewerGetFormat(viewer, &format)); 793 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 794 if (format == PETSC_VIEWER_NATIVE) { 795 if (dm->useNatural) { 796 if (dm->sfNatural) { 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 Vec v; 800 const char *vecname; 801 802 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 803 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 804 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 805 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 806 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 807 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 808 PetscCall(VecDestroy(&v)); 809 #else 810 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 811 #endif 812 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 813 } 814 } else PetscCall(VecLoad_Default(originalv, viewer)); 815 } 816 PetscFunctionReturn(PETSC_SUCCESS); 817 } 818 819 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 820 { 821 PetscSection coordSection; 822 Vec coordinates; 823 DMLabel depthLabel, celltypeLabel; 824 const char *name[4]; 825 const PetscScalar *a; 826 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 827 828 PetscFunctionBegin; 829 PetscCall(DMGetDimension(dm, &dim)); 830 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 831 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 832 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 833 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 834 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 835 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 836 PetscCall(VecGetArrayRead(coordinates, &a)); 837 name[0] = "vertex"; 838 name[1] = "edge"; 839 name[dim - 1] = "face"; 840 name[dim] = "cell"; 841 for (c = cStart; c < cEnd; ++c) { 842 PetscInt *closure = NULL; 843 PetscInt closureSize, cl, ct; 844 845 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 846 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 847 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 848 PetscCall(PetscViewerASCIIPushTab(viewer)); 849 for (cl = 0; cl < closureSize * 2; cl += 2) { 850 PetscInt point = closure[cl], depth, dof, off, d, p; 851 852 if ((point < pStart) || (point >= pEnd)) continue; 853 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 854 if (!dof) continue; 855 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 856 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 858 for (p = 0; p < dof / dim; ++p) { 859 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 860 for (d = 0; d < dim; ++d) { 861 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 862 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 863 } 864 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 865 } 866 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 867 } 868 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 869 PetscCall(PetscViewerASCIIPopTab(viewer)); 870 } 871 PetscCall(VecRestoreArrayRead(coordinates, &a)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 typedef enum { 876 CS_CARTESIAN, 877 CS_POLAR, 878 CS_CYLINDRICAL, 879 CS_SPHERICAL 880 } CoordSystem; 881 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 882 883 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 884 { 885 PetscInt i; 886 887 PetscFunctionBegin; 888 if (dim > 3) { 889 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 890 } else { 891 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 892 893 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 894 switch (cs) { 895 case CS_CARTESIAN: 896 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 897 break; 898 case CS_POLAR: 899 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 900 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 901 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 902 break; 903 case CS_CYLINDRICAL: 904 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 905 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 906 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 907 trcoords[2] = coords[2]; 908 break; 909 case CS_SPHERICAL: 910 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 911 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 912 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 913 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 914 break; 915 } 916 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 917 } 918 PetscFunctionReturn(PETSC_SUCCESS); 919 } 920 921 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 922 { 923 DM_Plex *mesh = (DM_Plex *)dm->data; 924 DM cdm, cdmCell; 925 PetscSection coordSection, coordSectionCell; 926 Vec coordinates, coordinatesCell; 927 PetscViewerFormat format; 928 929 PetscFunctionBegin; 930 PetscCall(PetscViewerGetFormat(viewer, &format)); 931 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 932 const char *name; 933 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 934 PetscInt pStart, pEnd, p, numLabels, l; 935 PetscMPIInt rank, size; 936 937 PetscCall(DMGetCoordinateDM(dm, &cdm)); 938 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 939 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 940 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 941 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 942 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 943 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 944 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 945 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 946 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 947 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 948 PetscCall(DMGetDimension(dm, &dim)); 949 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 950 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 951 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 952 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 953 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 954 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 955 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 956 for (p = pStart; p < pEnd; ++p) { 957 PetscInt dof, off, s; 958 959 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 960 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 961 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 962 } 963 PetscCall(PetscViewerFlush(viewer)); 964 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 965 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 966 for (p = pStart; p < pEnd; ++p) { 967 PetscInt dof, off, c; 968 969 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 970 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 971 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 972 } 973 PetscCall(PetscViewerFlush(viewer)); 974 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 975 if (coordSection && coordinates) { 976 CoordSystem cs = CS_CARTESIAN; 977 const PetscScalar *array, *arrayCell = NULL; 978 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 979 PetscMPIInt rank; 980 const char *name; 981 982 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 983 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 984 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 985 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 986 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 987 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 988 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 989 pStart = PetscMin(pvStart, pcStart); 990 pEnd = PetscMax(pvEnd, pcEnd); 991 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 992 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 994 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 995 996 PetscCall(VecGetArrayRead(coordinates, &array)); 997 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 998 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 999 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1000 for (p = pStart; p < pEnd; ++p) { 1001 PetscInt dof, off; 1002 1003 if (p >= pvStart && p < pvEnd) { 1004 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1005 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1006 if (dof) { 1007 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1008 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1009 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1010 } 1011 } 1012 if (cdmCell && p >= pcStart && p < pcEnd) { 1013 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1014 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1015 if (dof) { 1016 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1017 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1018 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1019 } 1020 } 1021 } 1022 PetscCall(PetscViewerFlush(viewer)); 1023 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1024 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1025 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1026 } 1027 PetscCall(DMGetNumLabels(dm, &numLabels)); 1028 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1029 for (l = 0; l < numLabels; ++l) { 1030 DMLabel label; 1031 PetscBool isdepth; 1032 const char *name; 1033 1034 PetscCall(DMGetLabelName(dm, l, &name)); 1035 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1036 if (isdepth) continue; 1037 PetscCall(DMGetLabel(dm, name, &label)); 1038 PetscCall(DMLabelView(label, viewer)); 1039 } 1040 if (size > 1) { 1041 PetscSF sf; 1042 1043 PetscCall(DMGetPointSF(dm, &sf)); 1044 PetscCall(PetscSFView(sf, viewer)); 1045 } 1046 if (mesh->periodic.face_sfs) 1047 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1048 PetscCall(PetscViewerFlush(viewer)); 1049 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1050 const char *name, *color; 1051 const char *defcolors[3] = {"gray", "orange", "green"}; 1052 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1053 char lname[PETSC_MAX_PATH_LEN]; 1054 PetscReal scale = 2.0; 1055 PetscReal tikzscale = 1.0; 1056 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1057 double tcoords[3]; 1058 PetscScalar *coords; 1059 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 1060 PetscMPIInt rank, size; 1061 char **names, **colors, **lcolors; 1062 PetscBool flg, lflg; 1063 PetscBT wp = NULL; 1064 PetscInt pEnd, pStart; 1065 1066 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1069 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1070 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1071 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1072 PetscCall(DMGetDimension(dm, &dim)); 1073 PetscCall(DMPlexGetDepth(dm, &depth)); 1074 PetscCall(DMGetNumLabels(dm, &numLabels)); 1075 numLabels = PetscMax(numLabels, 10); 1076 numColors = 10; 1077 numLColors = 10; 1078 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1080 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1081 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1082 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1083 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1084 n = 4; 1085 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1086 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1087 n = 4; 1088 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1089 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1090 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1091 if (!useLabels) numLabels = 0; 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1093 if (!useColors) { 1094 numColors = 3; 1095 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1096 } 1097 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1098 if (!useColors) { 1099 numLColors = 4; 1100 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1101 } 1102 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1103 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1104 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1105 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1106 if (depth < dim) plotEdges = PETSC_FALSE; 1107 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1108 1109 /* filter points with labelvalue != labeldefaultvalue */ 1110 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1112 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1113 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1114 if (lflg) { 1115 DMLabel lbl; 1116 1117 PetscCall(DMGetLabel(dm, lname, &lbl)); 1118 if (lbl) { 1119 PetscInt val, defval; 1120 1121 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1122 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1123 for (c = pStart; c < pEnd; c++) { 1124 PetscInt *closure = NULL; 1125 PetscInt closureSize; 1126 1127 PetscCall(DMLabelGetValue(lbl, c, &val)); 1128 if (val == defval) continue; 1129 1130 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1131 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1132 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1133 } 1134 } 1135 } 1136 1137 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1138 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1139 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1140 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1141 \\documentclass[tikz]{standalone}\n\n\ 1142 \\usepackage{pgflibraryshapes}\n\ 1143 \\usetikzlibrary{backgrounds}\n\ 1144 \\usetikzlibrary{arrows}\n\ 1145 \\begin{document}\n")); 1146 if (size > 1) { 1147 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1148 for (p = 0; p < size; ++p) { 1149 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1150 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1151 } 1152 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1153 } 1154 if (drawHasse) { 1155 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1156 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1169 } 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1171 1172 /* Plot vertices */ 1173 PetscCall(VecGetArray(coordinates, &coords)); 1174 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1175 for (v = vStart; v < vEnd; ++v) { 1176 PetscInt off, dof, d; 1177 PetscBool isLabeled = PETSC_FALSE; 1178 1179 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1180 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1181 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1182 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1183 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1184 for (d = 0; d < dof; ++d) { 1185 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1186 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1187 } 1188 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1189 if (dim == 3) { 1190 PetscReal tmp = tcoords[1]; 1191 tcoords[1] = tcoords[2]; 1192 tcoords[2] = -tmp; 1193 } 1194 for (d = 0; d < dof; ++d) { 1195 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1196 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1197 } 1198 if (drawHasse) color = colors[0 % numColors]; 1199 else color = colors[rank % numColors]; 1200 for (l = 0; l < numLabels; ++l) { 1201 PetscInt val; 1202 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1203 if (val >= 0) { 1204 color = lcolors[l % numLColors]; 1205 isLabeled = PETSC_TRUE; 1206 break; 1207 } 1208 } 1209 if (drawNumbers[0]) { 1210 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1211 } else if (drawColors[0]) { 1212 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1213 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1214 } 1215 PetscCall(VecRestoreArray(coordinates, &coords)); 1216 PetscCall(PetscViewerFlush(viewer)); 1217 /* Plot edges */ 1218 if (plotEdges) { 1219 PetscCall(VecGetArray(coordinates, &coords)); 1220 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1221 for (e = eStart; e < eEnd; ++e) { 1222 const PetscInt *cone; 1223 PetscInt coneSize, offA, offB, dof, d; 1224 1225 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1226 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1227 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1228 PetscCall(DMPlexGetCone(dm, e, &cone)); 1229 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1230 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1231 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1232 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1233 for (d = 0; d < dof; ++d) { 1234 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1235 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1236 } 1237 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1238 if (dim == 3) { 1239 PetscReal tmp = tcoords[1]; 1240 tcoords[1] = tcoords[2]; 1241 tcoords[2] = -tmp; 1242 } 1243 for (d = 0; d < dof; ++d) { 1244 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1245 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1246 } 1247 if (drawHasse) color = colors[1 % numColors]; 1248 else color = colors[rank % numColors]; 1249 for (l = 0; l < numLabels; ++l) { 1250 PetscInt val; 1251 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1252 if (val >= 0) { 1253 color = lcolors[l % numLColors]; 1254 break; 1255 } 1256 } 1257 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1258 } 1259 PetscCall(VecRestoreArray(coordinates, &coords)); 1260 PetscCall(PetscViewerFlush(viewer)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1262 } 1263 /* Plot cells */ 1264 if (dim == 3 || !drawNumbers[1]) { 1265 for (e = eStart; e < eEnd; ++e) { 1266 const PetscInt *cone; 1267 1268 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1269 color = colors[rank % numColors]; 1270 for (l = 0; l < numLabels; ++l) { 1271 PetscInt val; 1272 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1273 if (val >= 0) { 1274 color = lcolors[l % numLColors]; 1275 break; 1276 } 1277 } 1278 PetscCall(DMPlexGetCone(dm, e, &cone)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1280 } 1281 } else { 1282 DMPolytopeType ct; 1283 1284 /* Drawing a 2D polygon */ 1285 for (c = cStart; c < cEnd; ++c) { 1286 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1287 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1288 if (DMPolytopeTypeIsHybrid(ct)) { 1289 const PetscInt *cone; 1290 PetscInt coneSize, e; 1291 1292 PetscCall(DMPlexGetCone(dm, c, &cone)); 1293 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1294 for (e = 0; e < coneSize; ++e) { 1295 const PetscInt *econe; 1296 1297 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1298 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)); 1299 } 1300 } else { 1301 PetscInt *closure = NULL; 1302 PetscInt closureSize, Nv = 0, v; 1303 1304 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1305 for (p = 0; p < closureSize * 2; p += 2) { 1306 const PetscInt point = closure[p]; 1307 1308 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1309 } 1310 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1311 for (v = 0; v <= Nv; ++v) { 1312 const PetscInt vertex = closure[v % Nv]; 1313 1314 if (v > 0) { 1315 if (plotEdges) { 1316 const PetscInt *edge; 1317 PetscInt endpoints[2], ne; 1318 1319 endpoints[0] = closure[v - 1]; 1320 endpoints[1] = vertex; 1321 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1322 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1323 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1324 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1325 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1326 } 1327 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1328 } 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1330 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1331 } 1332 } 1333 } 1334 for (c = cStart; c < cEnd; ++c) { 1335 double ccoords[3] = {0.0, 0.0, 0.0}; 1336 PetscBool isLabeled = PETSC_FALSE; 1337 PetscScalar *cellCoords = NULL; 1338 const PetscScalar *array; 1339 PetscInt numCoords, cdim, d; 1340 PetscBool isDG; 1341 1342 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1343 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1344 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1345 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1346 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1347 for (p = 0; p < numCoords / cdim; ++p) { 1348 for (d = 0; d < cdim; ++d) { 1349 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1350 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1351 } 1352 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1353 if (cdim == 3) { 1354 PetscReal tmp = tcoords[1]; 1355 tcoords[1] = tcoords[2]; 1356 tcoords[2] = -tmp; 1357 } 1358 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1359 } 1360 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1361 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1362 for (d = 0; d < cdim; ++d) { 1363 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1364 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1365 } 1366 if (drawHasse) color = colors[depth % numColors]; 1367 else color = colors[rank % numColors]; 1368 for (l = 0; l < numLabels; ++l) { 1369 PetscInt val; 1370 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1371 if (val >= 0) { 1372 color = lcolors[l % numLColors]; 1373 isLabeled = PETSC_TRUE; 1374 break; 1375 } 1376 } 1377 if (drawNumbers[dim]) { 1378 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1379 } else if (drawColors[dim]) { 1380 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1381 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1382 } 1383 if (drawHasse) { 1384 color = colors[depth % numColors]; 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1388 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1389 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1390 1391 color = colors[1 % numColors]; 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1397 1398 color = colors[0 % numColors]; 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1404 1405 for (p = pStart; p < pEnd; ++p) { 1406 const PetscInt *cone; 1407 PetscInt coneSize, cp; 1408 1409 PetscCall(DMPlexGetCone(dm, p, &cone)); 1410 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1411 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1412 } 1413 } 1414 PetscCall(PetscViewerFlush(viewer)); 1415 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1418 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1419 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1420 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1421 PetscCall(PetscFree3(names, colors, lcolors)); 1422 PetscCall(PetscBTDestroy(&wp)); 1423 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1424 Vec cown, acown; 1425 VecScatter sct; 1426 ISLocalToGlobalMapping g2l; 1427 IS gid, acis; 1428 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1429 MPI_Group ggroup, ngroup; 1430 PetscScalar *array, nid; 1431 const PetscInt *idxs; 1432 PetscInt *idxs2, *start, *adjacency, *work; 1433 PetscInt64 lm[3], gm[3]; 1434 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1435 PetscMPIInt d1, d2, rank; 1436 1437 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1438 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1439 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1440 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1441 #endif 1442 if (ncomm != MPI_COMM_NULL) { 1443 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1444 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1445 d1 = 0; 1446 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1447 nid = d2; 1448 PetscCallMPI(MPI_Group_free(&ggroup)); 1449 PetscCallMPI(MPI_Group_free(&ngroup)); 1450 PetscCallMPI(MPI_Comm_free(&ncomm)); 1451 } else nid = 0.0; 1452 1453 /* Get connectivity */ 1454 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1455 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1456 1457 /* filter overlapped local cells */ 1458 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1459 PetscCall(ISGetIndices(gid, &idxs)); 1460 PetscCall(ISGetLocalSize(gid, &cum)); 1461 PetscCall(PetscMalloc1(cum, &idxs2)); 1462 for (c = cStart, cum = 0; c < cEnd; c++) { 1463 if (idxs[c - cStart] < 0) continue; 1464 idxs2[cum++] = idxs[c - cStart]; 1465 } 1466 PetscCall(ISRestoreIndices(gid, &idxs)); 1467 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1468 PetscCall(ISDestroy(&gid)); 1469 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1470 1471 /* support for node-aware cell locality */ 1472 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1473 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1474 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1475 PetscCall(VecGetArray(cown, &array)); 1476 for (c = 0; c < numVertices; c++) array[c] = nid; 1477 PetscCall(VecRestoreArray(cown, &array)); 1478 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1479 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1480 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1481 PetscCall(ISDestroy(&acis)); 1482 PetscCall(VecScatterDestroy(&sct)); 1483 PetscCall(VecDestroy(&cown)); 1484 1485 /* compute edgeCut */ 1486 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1487 PetscCall(PetscMalloc1(cum, &work)); 1488 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1489 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1490 PetscCall(ISDestroy(&gid)); 1491 PetscCall(VecGetArray(acown, &array)); 1492 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1493 PetscInt totl; 1494 1495 totl = start[c + 1] - start[c]; 1496 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1497 for (i = 0; i < totl; i++) { 1498 if (work[i] < 0) { 1499 ect += 1; 1500 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1501 } 1502 } 1503 } 1504 PetscCall(PetscFree(work)); 1505 PetscCall(VecRestoreArray(acown, &array)); 1506 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1507 lm[1] = -numVertices; 1508 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1510 lm[0] = ect; /* edgeCut */ 1511 lm[1] = ectn; /* node-aware edgeCut */ 1512 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1513 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1514 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1515 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1516 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1517 #else 1518 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1519 #endif 1520 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1521 PetscCall(PetscFree(start)); 1522 PetscCall(PetscFree(adjacency)); 1523 PetscCall(VecDestroy(&acown)); 1524 } else { 1525 const char *name; 1526 PetscInt *sizes, *hybsizes, *ghostsizes; 1527 PetscInt locDepth, depth, cellHeight, dim, d; 1528 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1529 PetscInt numLabels, l, maxSize = 17; 1530 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1531 MPI_Comm comm; 1532 PetscMPIInt size, rank; 1533 1534 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1535 PetscCallMPI(MPI_Comm_size(comm, &size)); 1536 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1537 PetscCall(DMGetDimension(dm, &dim)); 1538 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1539 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1540 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1541 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1542 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1543 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1544 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1545 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1546 gcNum = gcEnd - gcStart; 1547 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1548 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1549 for (d = 0; d <= depth; d++) { 1550 PetscInt Nc[2] = {0, 0}, ict; 1551 1552 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1553 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1554 ict = ct0; 1555 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1556 ct0 = (DMPolytopeType)ict; 1557 for (p = pStart; p < pEnd; ++p) { 1558 DMPolytopeType ct; 1559 1560 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1561 if (ct == ct0) ++Nc[0]; 1562 else ++Nc[1]; 1563 } 1564 if (size < maxSize) { 1565 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1566 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1567 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1568 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1569 for (p = 0; p < size; ++p) { 1570 if (rank == 0) { 1571 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1572 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1573 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1574 } 1575 } 1576 } else { 1577 PetscInt locMinMax[2]; 1578 1579 locMinMax[0] = Nc[0] + Nc[1]; 1580 locMinMax[1] = Nc[0] + Nc[1]; 1581 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1582 locMinMax[0] = Nc[1]; 1583 locMinMax[1] = Nc[1]; 1584 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1585 if (d == depth) { 1586 locMinMax[0] = gcNum; 1587 locMinMax[1] = gcNum; 1588 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1589 } 1590 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1591 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1592 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1593 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1594 } 1595 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1596 } 1597 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1598 { 1599 const PetscReal *maxCell; 1600 const PetscReal *L; 1601 PetscBool localized; 1602 1603 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1604 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1605 if (L || localized) { 1606 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1607 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1608 if (L) { 1609 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1610 for (d = 0; d < dim; ++d) { 1611 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1612 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1613 } 1614 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1615 } 1616 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1617 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1618 } 1619 } 1620 PetscCall(DMGetNumLabels(dm, &numLabels)); 1621 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1622 for (l = 0; l < numLabels; ++l) { 1623 DMLabel label; 1624 const char *name; 1625 IS valueIS; 1626 const PetscInt *values; 1627 PetscInt numValues, v; 1628 1629 PetscCall(DMGetLabelName(dm, l, &name)); 1630 PetscCall(DMGetLabel(dm, name, &label)); 1631 PetscCall(DMLabelGetNumValues(label, &numValues)); 1632 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1633 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1634 PetscCall(ISGetIndices(valueIS, &values)); 1635 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1636 for (v = 0; v < numValues; ++v) { 1637 PetscInt size; 1638 1639 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1640 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1641 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1642 } 1643 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1644 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1645 PetscCall(ISRestoreIndices(valueIS, &values)); 1646 PetscCall(ISDestroy(&valueIS)); 1647 } 1648 { 1649 char **labelNames; 1650 PetscInt Nl = numLabels; 1651 PetscBool flg; 1652 1653 PetscCall(PetscMalloc1(Nl, &labelNames)); 1654 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1655 for (l = 0; l < Nl; ++l) { 1656 DMLabel label; 1657 1658 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1659 if (flg) { 1660 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1661 PetscCall(DMLabelView(label, viewer)); 1662 } 1663 PetscCall(PetscFree(labelNames[l])); 1664 } 1665 PetscCall(PetscFree(labelNames)); 1666 } 1667 /* If no fields are specified, people do not want to see adjacency */ 1668 if (dm->Nf) { 1669 PetscInt f; 1670 1671 for (f = 0; f < dm->Nf; ++f) { 1672 const char *name; 1673 1674 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1675 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1676 PetscCall(PetscViewerASCIIPushTab(viewer)); 1677 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1678 if (dm->fields[f].adjacency[0]) { 1679 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1680 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1681 } else { 1682 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1683 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1684 } 1685 PetscCall(PetscViewerASCIIPopTab(viewer)); 1686 } 1687 } 1688 PetscCall(DMGetCoarseDM(dm, &cdm)); 1689 if (cdm) { 1690 PetscCall(PetscViewerASCIIPushTab(viewer)); 1691 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1692 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1693 PetscCall(PetscViewerASCIIPopTab(viewer)); 1694 } 1695 } 1696 PetscFunctionReturn(PETSC_SUCCESS); 1697 } 1698 1699 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1700 { 1701 DMPolytopeType ct; 1702 PetscMPIInt rank; 1703 PetscInt cdim; 1704 1705 PetscFunctionBegin; 1706 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1707 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1708 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1709 switch (ct) { 1710 case DM_POLYTOPE_SEGMENT: 1711 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1712 switch (cdim) { 1713 case 1: { 1714 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1715 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1716 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1718 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1719 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1720 } break; 1721 case 2: { 1722 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1723 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1724 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1725 1726 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1727 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)); 1728 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)); 1729 } break; 1730 default: 1731 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1732 } 1733 break; 1734 case DM_POLYTOPE_TRIANGLE: 1735 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)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1738 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1739 break; 1740 case DM_POLYTOPE_QUADRILATERAL: 1741 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)); 1742 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)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1746 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1747 break; 1748 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1749 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)); 1750 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)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1754 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1755 break; 1756 case DM_POLYTOPE_FV_GHOST: 1757 break; 1758 default: 1759 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1760 } 1761 PetscFunctionReturn(PETSC_SUCCESS); 1762 } 1763 1764 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1765 { 1766 PetscReal centroid[2] = {0., 0.}; 1767 PetscMPIInt rank; 1768 PetscInt fillColor; 1769 1770 PetscFunctionBegin; 1771 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1772 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1773 for (PetscInt v = 0; v < Nv; ++v) { 1774 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1775 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1776 } 1777 for (PetscInt e = 0; e < Nv; ++e) { 1778 refCoords[0] = refVertices[e * 2 + 0]; 1779 refCoords[1] = refVertices[e * 2 + 1]; 1780 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1781 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1782 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1783 } 1784 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1785 for (PetscInt d = 0; d < edgeDiv; ++d) { 1786 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)); 1787 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1788 } 1789 } 1790 PetscFunctionReturn(PETSC_SUCCESS); 1791 } 1792 1793 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1794 { 1795 DMPolytopeType ct; 1796 1797 PetscFunctionBegin; 1798 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1799 switch (ct) { 1800 case DM_POLYTOPE_TRIANGLE: { 1801 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1802 1803 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1804 } break; 1805 case DM_POLYTOPE_QUADRILATERAL: { 1806 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1807 1808 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1809 } break; 1810 default: 1811 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1812 } 1813 PetscFunctionReturn(PETSC_SUCCESS); 1814 } 1815 1816 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1817 { 1818 PetscDraw draw; 1819 DM cdm; 1820 PetscSection coordSection; 1821 Vec coordinates; 1822 PetscReal xyl[3], xyr[3]; 1823 PetscReal *refCoords, *edgeCoords; 1824 PetscBool isnull, drawAffine; 1825 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1826 1827 PetscFunctionBegin; 1828 PetscCall(DMGetCoordinateDim(dm, &dim)); 1829 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1830 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1831 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1832 edgeDiv = cDegree + 1; 1833 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1834 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1835 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1836 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1837 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1838 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1839 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1840 1841 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1842 PetscCall(PetscDrawIsNull(draw, &isnull)); 1843 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1844 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1845 1846 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1847 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1848 PetscCall(PetscDrawClear(draw)); 1849 1850 for (c = cStart; c < cEnd; ++c) { 1851 PetscScalar *coords = NULL; 1852 const PetscScalar *coords_arr; 1853 PetscInt numCoords; 1854 PetscBool isDG; 1855 1856 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1857 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1858 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1859 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1860 } 1861 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1862 PetscCall(PetscDrawFlush(draw)); 1863 PetscCall(PetscDrawPause(draw)); 1864 PetscCall(PetscDrawSave(draw)); 1865 PetscFunctionReturn(PETSC_SUCCESS); 1866 } 1867 1868 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1869 { 1870 DM odm = dm, rdm = dm, cdm; 1871 PetscFE fe; 1872 PetscSpace sp; 1873 PetscClassId id; 1874 PetscInt degree; 1875 PetscBool hoView = PETSC_TRUE; 1876 1877 PetscFunctionBegin; 1878 PetscObjectOptionsBegin((PetscObject)dm); 1879 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1880 PetscOptionsEnd(); 1881 PetscCall(PetscObjectReference((PetscObject)dm)); 1882 *hdm = dm; 1883 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1884 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1885 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1886 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1887 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1888 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1889 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1890 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1891 DM cdm, rcdm; 1892 Mat In; 1893 Vec cl, rcl; 1894 1895 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1896 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1897 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1898 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1899 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1900 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1901 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1902 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1903 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1904 PetscCall(MatMult(In, cl, rcl)); 1905 PetscCall(MatDestroy(&In)); 1906 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1907 PetscCall(DMDestroy(&odm)); 1908 odm = rdm; 1909 } 1910 *hdm = rdm; 1911 PetscFunctionReturn(PETSC_SUCCESS); 1912 } 1913 1914 #if defined(PETSC_HAVE_EXODUSII) 1915 #include <exodusII.h> 1916 #include <petscviewerexodusii.h> 1917 #endif 1918 1919 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1920 { 1921 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1922 char name[PETSC_MAX_PATH_LEN]; 1923 1924 PetscFunctionBegin; 1925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1926 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1927 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1928 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1929 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1930 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1931 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1932 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1933 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1934 if (iascii) { 1935 PetscViewerFormat format; 1936 PetscCall(PetscViewerGetFormat(viewer, &format)); 1937 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1938 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1939 } else if (ishdf5) { 1940 #if defined(PETSC_HAVE_HDF5) 1941 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1942 #else 1943 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1944 #endif 1945 } else if (isvtk) { 1946 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1947 } else if (isdraw) { 1948 DM hdm; 1949 1950 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1951 PetscCall(DMPlexView_Draw(hdm, viewer)); 1952 PetscCall(DMDestroy(&hdm)); 1953 } else if (isglvis) { 1954 PetscCall(DMPlexView_GLVis(dm, viewer)); 1955 #if defined(PETSC_HAVE_EXODUSII) 1956 } else if (isexodus) { 1957 /* 1958 exodusII requires that all sets be part of exactly one cell set. 1959 If the dm does not have a "Cell Sets" label defined, we create one 1960 with ID 1, containing all cells. 1961 Note that if the Cell Sets label is defined but does not cover all cells, 1962 we may still have a problem. This should probably be checked here or in the viewer; 1963 */ 1964 PetscInt numCS; 1965 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1966 if (!numCS) { 1967 PetscInt cStart, cEnd, c; 1968 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1969 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1970 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1971 } 1972 PetscCall(DMView_PlexExodusII(dm, viewer)); 1973 #endif 1974 #if defined(PETSC_HAVE_CGNS) 1975 } else if (iscgns) { 1976 PetscCall(DMView_PlexCGNS(dm, viewer)); 1977 #endif 1978 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1979 /* Optionally view the partition */ 1980 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1981 if (flg) { 1982 Vec ranks; 1983 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1984 PetscCall(VecView(ranks, viewer)); 1985 PetscCall(VecDestroy(&ranks)); 1986 } 1987 /* Optionally view a label */ 1988 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1989 if (flg) { 1990 DMLabel label; 1991 Vec val; 1992 1993 PetscCall(DMGetLabel(dm, name, &label)); 1994 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1995 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1996 PetscCall(VecView(val, viewer)); 1997 PetscCall(VecDestroy(&val)); 1998 } 1999 PetscFunctionReturn(PETSC_SUCCESS); 2000 } 2001 2002 /*@ 2003 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2004 2005 Collective 2006 2007 Input Parameters: 2008 + dm - The `DM` whose topology is to be saved 2009 - viewer - The `PetscViewer` to save it in 2010 2011 Level: advanced 2012 2013 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2014 @*/ 2015 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2016 { 2017 PetscBool ishdf5; 2018 2019 PetscFunctionBegin; 2020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2021 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2022 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2023 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2024 if (ishdf5) { 2025 #if defined(PETSC_HAVE_HDF5) 2026 PetscViewerFormat format; 2027 PetscCall(PetscViewerGetFormat(viewer, &format)); 2028 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2029 IS globalPointNumbering; 2030 2031 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2032 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2033 PetscCall(ISDestroy(&globalPointNumbering)); 2034 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2035 #else 2036 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2037 #endif 2038 } 2039 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2040 PetscFunctionReturn(PETSC_SUCCESS); 2041 } 2042 2043 /*@ 2044 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2045 2046 Collective 2047 2048 Input Parameters: 2049 + dm - The `DM` whose coordinates are to be saved 2050 - viewer - The `PetscViewer` for saving 2051 2052 Level: advanced 2053 2054 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2055 @*/ 2056 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2057 { 2058 PetscBool ishdf5; 2059 2060 PetscFunctionBegin; 2061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2062 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2063 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2064 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2065 if (ishdf5) { 2066 #if defined(PETSC_HAVE_HDF5) 2067 PetscViewerFormat format; 2068 PetscCall(PetscViewerGetFormat(viewer, &format)); 2069 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2070 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2071 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2072 #else 2073 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2074 #endif 2075 } 2076 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2077 PetscFunctionReturn(PETSC_SUCCESS); 2078 } 2079 2080 /*@ 2081 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2082 2083 Collective 2084 2085 Input Parameters: 2086 + dm - The `DM` whose labels are to be saved 2087 - viewer - The `PetscViewer` for saving 2088 2089 Level: advanced 2090 2091 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2092 @*/ 2093 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2094 { 2095 PetscBool ishdf5; 2096 2097 PetscFunctionBegin; 2098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2099 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2100 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2101 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2102 if (ishdf5) { 2103 #if defined(PETSC_HAVE_HDF5) 2104 IS globalPointNumbering; 2105 PetscViewerFormat format; 2106 2107 PetscCall(PetscViewerGetFormat(viewer, &format)); 2108 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2109 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2110 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2111 PetscCall(ISDestroy(&globalPointNumbering)); 2112 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2113 #else 2114 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2115 #endif 2116 } 2117 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2118 PetscFunctionReturn(PETSC_SUCCESS); 2119 } 2120 2121 /*@ 2122 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2123 2124 Collective 2125 2126 Input Parameters: 2127 + dm - The `DM` that contains the topology on which the section to be saved is defined 2128 . viewer - The `PetscViewer` for saving 2129 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2130 2131 Level: advanced 2132 2133 Notes: 2134 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. 2135 2136 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. 2137 2138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2139 @*/ 2140 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2141 { 2142 PetscBool ishdf5; 2143 2144 PetscFunctionBegin; 2145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2146 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2147 if (!sectiondm) sectiondm = dm; 2148 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2149 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2150 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2151 if (ishdf5) { 2152 #if defined(PETSC_HAVE_HDF5) 2153 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2154 #else 2155 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2156 #endif 2157 } 2158 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2159 PetscFunctionReturn(PETSC_SUCCESS); 2160 } 2161 2162 /*@ 2163 DMPlexGlobalVectorView - Saves a global vector 2164 2165 Collective 2166 2167 Input Parameters: 2168 + dm - The `DM` that represents the topology 2169 . viewer - The `PetscViewer` to save data with 2170 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2171 - vec - The global vector to be saved 2172 2173 Level: advanced 2174 2175 Notes: 2176 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. 2177 2178 Calling sequence: 2179 .vb 2180 DMCreate(PETSC_COMM_WORLD, &dm); 2181 DMSetType(dm, DMPLEX); 2182 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2183 DMClone(dm, §iondm); 2184 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2185 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2186 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2187 PetscSectionSetChart(section, pStart, pEnd); 2188 PetscSectionSetUp(section); 2189 DMSetLocalSection(sectiondm, section); 2190 PetscSectionDestroy(§ion); 2191 DMGetGlobalVector(sectiondm, &vec); 2192 PetscObjectSetName((PetscObject)vec, "vec_name"); 2193 DMPlexTopologyView(dm, viewer); 2194 DMPlexSectionView(dm, viewer, sectiondm); 2195 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2196 DMRestoreGlobalVector(sectiondm, &vec); 2197 DMDestroy(§iondm); 2198 DMDestroy(&dm); 2199 .ve 2200 2201 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2202 @*/ 2203 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2204 { 2205 PetscBool ishdf5; 2206 2207 PetscFunctionBegin; 2208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2209 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2210 if (!sectiondm) sectiondm = dm; 2211 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2212 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2213 /* Check consistency */ 2214 { 2215 PetscSection section; 2216 PetscBool includesConstraints; 2217 PetscInt m, m1; 2218 2219 PetscCall(VecGetLocalSize(vec, &m1)); 2220 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2221 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2222 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2223 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2224 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2225 } 2226 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2227 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2228 if (ishdf5) { 2229 #if defined(PETSC_HAVE_HDF5) 2230 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2231 #else 2232 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2233 #endif 2234 } 2235 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2236 PetscFunctionReturn(PETSC_SUCCESS); 2237 } 2238 2239 /*@ 2240 DMPlexLocalVectorView - Saves a local vector 2241 2242 Collective 2243 2244 Input Parameters: 2245 + dm - The `DM` that represents the topology 2246 . viewer - The `PetscViewer` to save data with 2247 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2248 - vec - The local vector to be saved 2249 2250 Level: advanced 2251 2252 Note: 2253 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. 2254 2255 Calling sequence: 2256 .vb 2257 DMCreate(PETSC_COMM_WORLD, &dm); 2258 DMSetType(dm, DMPLEX); 2259 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2260 DMClone(dm, §iondm); 2261 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2262 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2263 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2264 PetscSectionSetChart(section, pStart, pEnd); 2265 PetscSectionSetUp(section); 2266 DMSetLocalSection(sectiondm, section); 2267 DMGetLocalVector(sectiondm, &vec); 2268 PetscObjectSetName((PetscObject)vec, "vec_name"); 2269 DMPlexTopologyView(dm, viewer); 2270 DMPlexSectionView(dm, viewer, sectiondm); 2271 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2272 DMRestoreLocalVector(sectiondm, &vec); 2273 DMDestroy(§iondm); 2274 DMDestroy(&dm); 2275 .ve 2276 2277 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2278 @*/ 2279 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2280 { 2281 PetscBool ishdf5; 2282 2283 PetscFunctionBegin; 2284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2285 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2286 if (!sectiondm) sectiondm = dm; 2287 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2288 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2289 /* Check consistency */ 2290 { 2291 PetscSection section; 2292 PetscBool includesConstraints; 2293 PetscInt m, m1; 2294 2295 PetscCall(VecGetLocalSize(vec, &m1)); 2296 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2297 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2298 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2299 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2300 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2301 } 2302 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2303 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2304 if (ishdf5) { 2305 #if defined(PETSC_HAVE_HDF5) 2306 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2307 #else 2308 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2309 #endif 2310 } 2311 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2312 PetscFunctionReturn(PETSC_SUCCESS); 2313 } 2314 2315 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2316 { 2317 PetscBool ishdf5; 2318 2319 PetscFunctionBegin; 2320 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2321 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2322 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2323 if (ishdf5) { 2324 #if defined(PETSC_HAVE_HDF5) 2325 PetscViewerFormat format; 2326 PetscCall(PetscViewerGetFormat(viewer, &format)); 2327 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2328 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2329 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2330 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2331 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2332 PetscFunctionReturn(PETSC_SUCCESS); 2333 #else 2334 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2335 #endif 2336 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2337 } 2338 2339 /*@ 2340 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2341 2342 Collective 2343 2344 Input Parameters: 2345 + dm - The `DM` into which the topology is loaded 2346 - viewer - The `PetscViewer` for the saved topology 2347 2348 Output Parameter: 2349 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded 2350 2351 Level: advanced 2352 2353 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2354 `PetscViewer`, `PetscSF` 2355 @*/ 2356 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2357 { 2358 PetscBool ishdf5; 2359 2360 PetscFunctionBegin; 2361 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2362 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2363 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2364 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2365 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2366 if (ishdf5) { 2367 #if defined(PETSC_HAVE_HDF5) 2368 PetscViewerFormat format; 2369 PetscCall(PetscViewerGetFormat(viewer, &format)); 2370 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2371 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2372 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2373 #else 2374 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2375 #endif 2376 } 2377 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2378 PetscFunctionReturn(PETSC_SUCCESS); 2379 } 2380 2381 /*@ 2382 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2383 2384 Collective 2385 2386 Input Parameters: 2387 + dm - The `DM` into which the coordinates are loaded 2388 . viewer - The `PetscViewer` for the saved coordinates 2389 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2390 2391 Level: advanced 2392 2393 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2394 `PetscSF`, `PetscViewer` 2395 @*/ 2396 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2397 { 2398 PetscBool ishdf5; 2399 2400 PetscFunctionBegin; 2401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2402 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2403 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2404 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2405 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2406 if (ishdf5) { 2407 #if defined(PETSC_HAVE_HDF5) 2408 PetscViewerFormat format; 2409 PetscCall(PetscViewerGetFormat(viewer, &format)); 2410 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2411 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2412 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2413 #else 2414 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2415 #endif 2416 } 2417 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2418 PetscFunctionReturn(PETSC_SUCCESS); 2419 } 2420 2421 /*@ 2422 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2423 2424 Collective 2425 2426 Input Parameters: 2427 + dm - The `DM` into which the labels are loaded 2428 . viewer - The `PetscViewer` for the saved labels 2429 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2430 2431 Level: advanced 2432 2433 Note: 2434 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2435 2436 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2437 `PetscSF`, `PetscViewer` 2438 @*/ 2439 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2440 { 2441 PetscBool ishdf5; 2442 2443 PetscFunctionBegin; 2444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2445 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2446 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2447 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2448 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2449 if (ishdf5) { 2450 #if defined(PETSC_HAVE_HDF5) 2451 PetscViewerFormat format; 2452 2453 PetscCall(PetscViewerGetFormat(viewer, &format)); 2454 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2455 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2456 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2457 #else 2458 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2459 #endif 2460 } 2461 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2462 PetscFunctionReturn(PETSC_SUCCESS); 2463 } 2464 2465 /*@ 2466 DMPlexSectionLoad - Loads section into a `DMPLEX` 2467 2468 Collective 2469 2470 Input Parameters: 2471 + dm - The `DM` that represents the topology 2472 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2473 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2474 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2475 2476 Output Parameters: 2477 + 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) 2478 - 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) 2479 2480 Level: advanced 2481 2482 Notes: 2483 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. 2484 2485 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. 2486 2487 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. 2488 2489 Example using 2 processes: 2490 .vb 2491 NX (number of points on dm): 4 2492 sectionA : the on-disk section 2493 vecA : a vector associated with sectionA 2494 sectionB : sectiondm's local section constructed in this function 2495 vecB (local) : a vector associated with sectiondm's local section 2496 vecB (global) : a vector associated with sectiondm's global section 2497 2498 rank 0 rank 1 2499 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2500 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2501 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2502 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2503 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2504 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2505 sectionB->atlasDof : 1 0 1 | 1 3 2506 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2507 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2508 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2509 .ve 2510 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2511 2512 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2513 @*/ 2514 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2515 { 2516 PetscBool ishdf5; 2517 2518 PetscFunctionBegin; 2519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2520 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2521 if (!sectiondm) sectiondm = dm; 2522 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2523 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2524 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2525 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2526 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2527 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2528 if (ishdf5) { 2529 #if defined(PETSC_HAVE_HDF5) 2530 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2531 #else 2532 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2533 #endif 2534 } 2535 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2536 PetscFunctionReturn(PETSC_SUCCESS); 2537 } 2538 2539 /*@ 2540 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2541 2542 Collective 2543 2544 Input Parameters: 2545 + dm - The `DM` that represents the topology 2546 . viewer - The `PetscViewer` that represents the on-disk vector data 2547 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2548 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2549 - vec - The global vector to set values of 2550 2551 Level: advanced 2552 2553 Notes: 2554 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. 2555 2556 Calling sequence: 2557 .vb 2558 DMCreate(PETSC_COMM_WORLD, &dm); 2559 DMSetType(dm, DMPLEX); 2560 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2561 DMPlexTopologyLoad(dm, viewer, &sfX); 2562 DMClone(dm, §iondm); 2563 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2564 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2565 DMGetGlobalVector(sectiondm, &vec); 2566 PetscObjectSetName((PetscObject)vec, "vec_name"); 2567 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2568 DMRestoreGlobalVector(sectiondm, &vec); 2569 PetscSFDestroy(&gsf); 2570 PetscSFDestroy(&sfX); 2571 DMDestroy(§iondm); 2572 DMDestroy(&dm); 2573 .ve 2574 2575 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2576 `PetscSF`, `PetscViewer` 2577 @*/ 2578 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2579 { 2580 PetscBool ishdf5; 2581 2582 PetscFunctionBegin; 2583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2584 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2585 if (!sectiondm) sectiondm = dm; 2586 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2587 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2588 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2589 /* Check consistency */ 2590 { 2591 PetscSection section; 2592 PetscBool includesConstraints; 2593 PetscInt m, m1; 2594 2595 PetscCall(VecGetLocalSize(vec, &m1)); 2596 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2597 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2598 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2599 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2600 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2601 } 2602 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2603 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2604 if (ishdf5) { 2605 #if defined(PETSC_HAVE_HDF5) 2606 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2607 #else 2608 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2609 #endif 2610 } 2611 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2612 PetscFunctionReturn(PETSC_SUCCESS); 2613 } 2614 2615 /*@ 2616 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2617 2618 Collective 2619 2620 Input Parameters: 2621 + dm - The `DM` that represents the topology 2622 . viewer - The `PetscViewer` that represents the on-disk vector data 2623 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2624 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2625 - vec - The local vector to set values of 2626 2627 Level: advanced 2628 2629 Notes: 2630 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. 2631 2632 Calling sequence: 2633 .vb 2634 DMCreate(PETSC_COMM_WORLD, &dm); 2635 DMSetType(dm, DMPLEX); 2636 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2637 DMPlexTopologyLoad(dm, viewer, &sfX); 2638 DMClone(dm, §iondm); 2639 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2640 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2641 DMGetLocalVector(sectiondm, &vec); 2642 PetscObjectSetName((PetscObject)vec, "vec_name"); 2643 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2644 DMRestoreLocalVector(sectiondm, &vec); 2645 PetscSFDestroy(&lsf); 2646 PetscSFDestroy(&sfX); 2647 DMDestroy(§iondm); 2648 DMDestroy(&dm); 2649 .ve 2650 2651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2652 `PetscSF`, `PetscViewer` 2653 @*/ 2654 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2655 { 2656 PetscBool ishdf5; 2657 2658 PetscFunctionBegin; 2659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2660 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2661 if (!sectiondm) sectiondm = dm; 2662 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2663 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2664 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2665 /* Check consistency */ 2666 { 2667 PetscSection section; 2668 PetscBool includesConstraints; 2669 PetscInt m, m1; 2670 2671 PetscCall(VecGetLocalSize(vec, &m1)); 2672 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2673 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2674 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2675 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2676 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2677 } 2678 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2679 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2680 if (ishdf5) { 2681 #if defined(PETSC_HAVE_HDF5) 2682 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2683 #else 2684 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2685 #endif 2686 } 2687 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2688 PetscFunctionReturn(PETSC_SUCCESS); 2689 } 2690 2691 PetscErrorCode DMDestroy_Plex(DM dm) 2692 { 2693 DM_Plex *mesh = (DM_Plex *)dm->data; 2694 2695 PetscFunctionBegin; 2696 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2697 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2698 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2699 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2700 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2701 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2702 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2703 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2704 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2705 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2706 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2707 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2708 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2709 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2710 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2711 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2712 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2713 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2714 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2715 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2716 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2717 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2718 PetscCall(PetscFree(mesh->cones)); 2719 PetscCall(PetscFree(mesh->coneOrientations)); 2720 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2721 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2722 PetscCall(PetscFree(mesh->supports)); 2723 PetscCall(PetscFree(mesh->cellTypes)); 2724 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2725 PetscCall(PetscFree(mesh->tetgenOpts)); 2726 PetscCall(PetscFree(mesh->triangleOpts)); 2727 PetscCall(PetscFree(mesh->transformType)); 2728 PetscCall(PetscFree(mesh->distributionName)); 2729 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2730 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2731 PetscCall(ISDestroy(&mesh->subpointIS)); 2732 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2733 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2734 if (mesh->periodic.face_sfs) { 2735 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2736 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2737 } 2738 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2739 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2740 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2741 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2742 PetscCall(ISDestroy(&mesh->anchorIS)); 2743 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2744 PetscCall(PetscFree(mesh->parents)); 2745 PetscCall(PetscFree(mesh->childIDs)); 2746 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2747 PetscCall(PetscFree(mesh->children)); 2748 PetscCall(DMDestroy(&mesh->referenceTree)); 2749 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2750 PetscCall(PetscFree(mesh->neighbors)); 2751 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2752 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2753 PetscCall(PetscFree(mesh)); 2754 PetscFunctionReturn(PETSC_SUCCESS); 2755 } 2756 2757 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2758 { 2759 PetscSection sectionGlobal, sectionLocal; 2760 PetscInt bs = -1, mbs; 2761 PetscInt localSize, localStart = 0; 2762 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2763 MatType mtype; 2764 ISLocalToGlobalMapping ltog; 2765 2766 PetscFunctionBegin; 2767 PetscCall(MatInitializePackage()); 2768 mtype = dm->mattype; 2769 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2770 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2771 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2772 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2773 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2774 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2775 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2776 PetscCall(MatSetType(*J, mtype)); 2777 PetscCall(MatSetFromOptions(*J)); 2778 PetscCall(MatGetBlockSize(*J, &mbs)); 2779 if (mbs > 1) bs = mbs; 2780 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2781 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2782 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2783 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2784 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2785 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2786 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2787 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2788 if (!isShell) { 2789 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2790 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2791 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2792 2793 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2794 2795 PetscCall(PetscCalloc1(localSize, &pblocks)); 2796 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2797 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2798 for (p = pStart; p < pEnd; ++p) { 2799 switch (dm->blocking_type) { 2800 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2801 PetscInt bdof, offset; 2802 2803 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2804 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2805 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2806 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2807 // Signal block concatenation 2808 if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof); 2809 dof = dof < 0 ? -(dof + 1) : dof; 2810 bdof = cdof && (dof - cdof) ? 1 : dof; 2811 if (dof) { 2812 if (bs < 0) { 2813 bs = bdof; 2814 } else if (bs != bdof) { 2815 bs = 1; 2816 } 2817 } 2818 } break; 2819 case DM_BLOCKING_FIELD_NODE: { 2820 for (PetscInt field = 0; field < num_fields; field++) { 2821 PetscInt num_comp, bdof, offset; 2822 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2823 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2824 if (dof < 0) continue; 2825 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2826 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2827 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); 2828 PetscInt num_nodes = dof / num_comp; 2829 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2830 // Handle possibly constant block size (unlikely) 2831 bdof = cdof && (dof - cdof) ? 1 : dof; 2832 if (dof) { 2833 if (bs < 0) { 2834 bs = bdof; 2835 } else if (bs != bdof) { 2836 bs = 1; 2837 } 2838 } 2839 } 2840 } break; 2841 } 2842 } 2843 /* Must have same blocksize on all procs (some might have no points) */ 2844 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2845 bsLocal[1] = bs; 2846 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2847 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2848 else bs = bsMinMax[0]; 2849 bs = PetscMax(1, bs); 2850 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2851 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2852 PetscCall(MatSetBlockSize(*J, bs)); 2853 PetscCall(MatSetUp(*J)); 2854 } else { 2855 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2856 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2857 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2858 } 2859 { // Consolidate blocks 2860 PetscInt nblocks = 0; 2861 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2862 if (pblocks[i] == 0) continue; 2863 // Negative block size indicates the blocks should be concatenated 2864 if (pblocks[i] < 0) { 2865 pblocks[i] = -pblocks[i]; 2866 pblocks[nblocks - 1] += pblocks[i]; 2867 } else { 2868 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2869 } 2870 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2871 } 2872 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2873 } 2874 PetscCall(PetscFree(pblocks)); 2875 } 2876 PetscCall(MatSetDM(*J, dm)); 2877 PetscFunctionReturn(PETSC_SUCCESS); 2878 } 2879 2880 /*@ 2881 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2882 2883 Not Collective 2884 2885 Input Parameter: 2886 . dm - The `DMPLEX` 2887 2888 Output Parameter: 2889 . subsection - The subdomain section 2890 2891 Level: developer 2892 2893 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2894 @*/ 2895 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2896 { 2897 DM_Plex *mesh = (DM_Plex *)dm->data; 2898 2899 PetscFunctionBegin; 2900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2901 if (!mesh->subdomainSection) { 2902 PetscSection section; 2903 PetscSF sf; 2904 2905 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2906 PetscCall(DMGetLocalSection(dm, §ion)); 2907 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2908 PetscCall(PetscSFDestroy(&sf)); 2909 } 2910 *subsection = mesh->subdomainSection; 2911 PetscFunctionReturn(PETSC_SUCCESS); 2912 } 2913 2914 /*@ 2915 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2916 2917 Not Collective 2918 2919 Input Parameter: 2920 . dm - The `DMPLEX` 2921 2922 Output Parameters: 2923 + pStart - The first mesh point 2924 - pEnd - The upper bound for mesh points 2925 2926 Level: beginner 2927 2928 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2929 @*/ 2930 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2931 { 2932 DM_Plex *mesh = (DM_Plex *)dm->data; 2933 2934 PetscFunctionBegin; 2935 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2936 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2937 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2938 PetscFunctionReturn(PETSC_SUCCESS); 2939 } 2940 2941 /*@ 2942 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2943 2944 Not Collective 2945 2946 Input Parameters: 2947 + dm - The `DMPLEX` 2948 . pStart - The first mesh point 2949 - pEnd - The upper bound for mesh points 2950 2951 Level: beginner 2952 2953 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2954 @*/ 2955 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2956 { 2957 DM_Plex *mesh = (DM_Plex *)dm->data; 2958 2959 PetscFunctionBegin; 2960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2961 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2962 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2963 PetscCall(PetscFree(mesh->cellTypes)); 2964 PetscFunctionReturn(PETSC_SUCCESS); 2965 } 2966 2967 /*@ 2968 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2969 2970 Not Collective 2971 2972 Input Parameters: 2973 + dm - The `DMPLEX` 2974 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2975 2976 Output Parameter: 2977 . size - The cone size for point `p` 2978 2979 Level: beginner 2980 2981 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2982 @*/ 2983 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2984 { 2985 DM_Plex *mesh = (DM_Plex *)dm->data; 2986 2987 PetscFunctionBegin; 2988 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2989 PetscAssertPointer(size, 3); 2990 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2991 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2992 PetscFunctionReturn(PETSC_SUCCESS); 2993 } 2994 2995 /*@ 2996 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2997 2998 Not Collective 2999 3000 Input Parameters: 3001 + dm - The `DMPLEX` 3002 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3003 - size - The cone size for point `p` 3004 3005 Level: beginner 3006 3007 Note: 3008 This should be called after `DMPlexSetChart()`. 3009 3010 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3011 @*/ 3012 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3013 { 3014 DM_Plex *mesh = (DM_Plex *)dm->data; 3015 3016 PetscFunctionBegin; 3017 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3018 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3019 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3020 PetscFunctionReturn(PETSC_SUCCESS); 3021 } 3022 3023 /*@C 3024 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3025 3026 Not Collective 3027 3028 Input Parameters: 3029 + dm - The `DMPLEX` 3030 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3031 3032 Output Parameter: 3033 . cone - An array of points which are on the in-edges for point `p` 3034 3035 Level: beginner 3036 3037 Fortran Notes: 3038 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3039 `DMPlexRestoreCone()` is not needed/available in C. 3040 3041 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3042 @*/ 3043 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3044 { 3045 DM_Plex *mesh = (DM_Plex *)dm->data; 3046 PetscInt off; 3047 3048 PetscFunctionBegin; 3049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3050 PetscAssertPointer(cone, 3); 3051 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3052 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3053 PetscFunctionReturn(PETSC_SUCCESS); 3054 } 3055 3056 /*@C 3057 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3058 3059 Not Collective 3060 3061 Input Parameters: 3062 + dm - The `DMPLEX` 3063 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3064 3065 Output Parameters: 3066 + pConesSection - `PetscSection` describing the layout of `pCones` 3067 - pCones - An array of points which are on the in-edges for the point set `p` 3068 3069 Level: intermediate 3070 3071 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3072 @*/ 3073 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3074 { 3075 PetscSection cs, newcs; 3076 PetscInt *cones; 3077 PetscInt *newarr = NULL; 3078 PetscInt n; 3079 3080 PetscFunctionBegin; 3081 PetscCall(DMPlexGetCones(dm, &cones)); 3082 PetscCall(DMPlexGetConeSection(dm, &cs)); 3083 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3084 if (pConesSection) *pConesSection = newcs; 3085 if (pCones) { 3086 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3087 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3088 } 3089 PetscFunctionReturn(PETSC_SUCCESS); 3090 } 3091 3092 /*@ 3093 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3094 3095 Not Collective 3096 3097 Input Parameters: 3098 + dm - The `DMPLEX` 3099 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3100 3101 Output Parameter: 3102 . expandedPoints - An array of vertices recursively expanded from input points 3103 3104 Level: advanced 3105 3106 Notes: 3107 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3108 3109 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3110 3111 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3112 `DMPlexGetDepth()`, `IS` 3113 @*/ 3114 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3115 { 3116 IS *expandedPointsAll; 3117 PetscInt depth; 3118 3119 PetscFunctionBegin; 3120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3121 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3122 PetscAssertPointer(expandedPoints, 3); 3123 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3124 *expandedPoints = expandedPointsAll[0]; 3125 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3126 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3127 PetscFunctionReturn(PETSC_SUCCESS); 3128 } 3129 3130 /*@ 3131 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 3132 3133 Not Collective 3134 3135 Input Parameters: 3136 + dm - The `DMPLEX` 3137 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3138 3139 Output Parameters: 3140 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3141 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3142 - sections - (optional) An array of sections which describe mappings from points to their cone points 3143 3144 Level: advanced 3145 3146 Notes: 3147 Like `DMPlexGetConeTuple()` but recursive. 3148 3149 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. 3150 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3151 3152 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\: 3153 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3154 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3155 3156 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3157 `DMPlexGetDepth()`, `PetscSection`, `IS` 3158 @*/ 3159 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3160 { 3161 const PetscInt *arr0 = NULL, *cone = NULL; 3162 PetscInt *arr = NULL, *newarr = NULL; 3163 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3164 IS *expandedPoints_; 3165 PetscSection *sections_; 3166 3167 PetscFunctionBegin; 3168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3169 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3170 if (depth) PetscAssertPointer(depth, 3); 3171 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3172 if (sections) PetscAssertPointer(sections, 5); 3173 PetscCall(ISGetLocalSize(points, &n)); 3174 PetscCall(ISGetIndices(points, &arr0)); 3175 PetscCall(DMPlexGetDepth(dm, &depth_)); 3176 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3177 PetscCall(PetscCalloc1(depth_, §ions_)); 3178 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3179 for (d = depth_ - 1; d >= 0; d--) { 3180 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3181 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3182 for (i = 0; i < n; i++) { 3183 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3184 if (arr[i] >= start && arr[i] < end) { 3185 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3186 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3187 } else { 3188 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3189 } 3190 } 3191 PetscCall(PetscSectionSetUp(sections_[d])); 3192 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3193 PetscCall(PetscMalloc1(newn, &newarr)); 3194 for (i = 0; i < n; i++) { 3195 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3196 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3197 if (cn > 1) { 3198 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3199 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3200 } else { 3201 newarr[co] = arr[i]; 3202 } 3203 } 3204 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3205 arr = newarr; 3206 n = newn; 3207 } 3208 PetscCall(ISRestoreIndices(points, &arr0)); 3209 *depth = depth_; 3210 if (expandedPoints) *expandedPoints = expandedPoints_; 3211 else { 3212 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3213 PetscCall(PetscFree(expandedPoints_)); 3214 } 3215 if (sections) *sections = sections_; 3216 else { 3217 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3218 PetscCall(PetscFree(sections_)); 3219 } 3220 PetscFunctionReturn(PETSC_SUCCESS); 3221 } 3222 3223 /*@ 3224 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3225 3226 Not Collective 3227 3228 Input Parameters: 3229 + dm - The `DMPLEX` 3230 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3231 3232 Output Parameters: 3233 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3234 . expandedPoints - (optional) An array of recursively expanded cones 3235 - sections - (optional) An array of sections which describe mappings from points to their cone points 3236 3237 Level: advanced 3238 3239 Note: 3240 See `DMPlexGetConeRecursive()` 3241 3242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3243 `DMPlexGetDepth()`, `IS`, `PetscSection` 3244 @*/ 3245 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3246 { 3247 PetscInt d, depth_; 3248 3249 PetscFunctionBegin; 3250 PetscCall(DMPlexGetDepth(dm, &depth_)); 3251 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3252 if (depth) *depth = 0; 3253 if (expandedPoints) { 3254 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3255 PetscCall(PetscFree(*expandedPoints)); 3256 } 3257 if (sections) { 3258 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3259 PetscCall(PetscFree(*sections)); 3260 } 3261 PetscFunctionReturn(PETSC_SUCCESS); 3262 } 3263 3264 /*@ 3265 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 3266 3267 Not Collective 3268 3269 Input Parameters: 3270 + dm - The `DMPLEX` 3271 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3272 - cone - An array of points which are on the in-edges for point `p` 3273 3274 Level: beginner 3275 3276 Note: 3277 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3278 3279 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3280 @*/ 3281 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3282 { 3283 DM_Plex *mesh = (DM_Plex *)dm->data; 3284 PetscInt dof, off, c; 3285 3286 PetscFunctionBegin; 3287 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3288 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3289 if (dof) PetscAssertPointer(cone, 3); 3290 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3291 if (PetscDefined(USE_DEBUG)) { 3292 PetscInt pStart, pEnd; 3293 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3294 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); 3295 for (c = 0; c < dof; ++c) { 3296 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); 3297 mesh->cones[off + c] = cone[c]; 3298 } 3299 } else { 3300 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3301 } 3302 PetscFunctionReturn(PETSC_SUCCESS); 3303 } 3304 3305 /*@C 3306 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3307 3308 Not Collective 3309 3310 Input Parameters: 3311 + dm - The `DMPLEX` 3312 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3313 3314 Output Parameter: 3315 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3316 integer giving the prescription for cone traversal. 3317 3318 Level: beginner 3319 3320 Note: 3321 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3322 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3323 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3324 with the identity. 3325 3326 Fortran Notes: 3327 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3328 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3329 3330 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3331 @*/ 3332 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3333 { 3334 DM_Plex *mesh = (DM_Plex *)dm->data; 3335 PetscInt off; 3336 3337 PetscFunctionBegin; 3338 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3339 if (PetscDefined(USE_DEBUG)) { 3340 PetscInt dof; 3341 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3342 if (dof) PetscAssertPointer(coneOrientation, 3); 3343 } 3344 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3345 3346 *coneOrientation = &mesh->coneOrientations[off]; 3347 PetscFunctionReturn(PETSC_SUCCESS); 3348 } 3349 3350 /*@ 3351 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3352 3353 Not Collective 3354 3355 Input Parameters: 3356 + dm - The `DMPLEX` 3357 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3358 - coneOrientation - An array of orientations 3359 3360 Level: beginner 3361 3362 Notes: 3363 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3364 3365 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3366 3367 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3368 @*/ 3369 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3370 { 3371 DM_Plex *mesh = (DM_Plex *)dm->data; 3372 PetscInt pStart, pEnd; 3373 PetscInt dof, off, c; 3374 3375 PetscFunctionBegin; 3376 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3377 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3378 if (dof) PetscAssertPointer(coneOrientation, 3); 3379 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3380 if (PetscDefined(USE_DEBUG)) { 3381 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3382 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); 3383 for (c = 0; c < dof; ++c) { 3384 PetscInt cdof, o = coneOrientation[c]; 3385 3386 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3387 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); 3388 mesh->coneOrientations[off + c] = o; 3389 } 3390 } else { 3391 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3392 } 3393 PetscFunctionReturn(PETSC_SUCCESS); 3394 } 3395 3396 /*@ 3397 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3398 3399 Not Collective 3400 3401 Input Parameters: 3402 + dm - The `DMPLEX` 3403 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3404 . conePos - The local index in the cone where the point should be put 3405 - conePoint - The mesh point to insert 3406 3407 Level: beginner 3408 3409 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3410 @*/ 3411 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3412 { 3413 DM_Plex *mesh = (DM_Plex *)dm->data; 3414 PetscInt pStart, pEnd; 3415 PetscInt dof, off; 3416 3417 PetscFunctionBegin; 3418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3419 if (PetscDefined(USE_DEBUG)) { 3420 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3421 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); 3422 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); 3423 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3424 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); 3425 } 3426 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3427 mesh->cones[off + conePos] = conePoint; 3428 PetscFunctionReturn(PETSC_SUCCESS); 3429 } 3430 3431 /*@ 3432 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3433 3434 Not Collective 3435 3436 Input Parameters: 3437 + dm - The `DMPLEX` 3438 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3439 . conePos - The local index in the cone where the point should be put 3440 - coneOrientation - The point orientation to insert 3441 3442 Level: beginner 3443 3444 Note: 3445 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3446 3447 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3448 @*/ 3449 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3450 { 3451 DM_Plex *mesh = (DM_Plex *)dm->data; 3452 PetscInt pStart, pEnd; 3453 PetscInt dof, off; 3454 3455 PetscFunctionBegin; 3456 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3457 if (PetscDefined(USE_DEBUG)) { 3458 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3459 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); 3460 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3461 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); 3462 } 3463 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3464 mesh->coneOrientations[off + conePos] = coneOrientation; 3465 PetscFunctionReturn(PETSC_SUCCESS); 3466 } 3467 3468 /*@C 3469 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3470 3471 Not collective 3472 3473 Input Parameters: 3474 + dm - The DMPlex 3475 - p - The point, which must lie in the chart set with DMPlexSetChart() 3476 3477 Output Parameters: 3478 + cone - An array of points which are on the in-edges for point `p` 3479 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3480 integer giving the prescription for cone traversal. 3481 3482 Level: beginner 3483 3484 Notes: 3485 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3486 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3487 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3488 with the identity. 3489 3490 Fortran Notes: 3491 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3492 `DMPlexRestoreCone()` is not needed/available in C. 3493 3494 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3495 @*/ 3496 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3497 { 3498 DM_Plex *mesh = (DM_Plex *)dm->data; 3499 3500 PetscFunctionBegin; 3501 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3502 if (mesh->tr) { 3503 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3504 } else { 3505 PetscInt off; 3506 if (PetscDefined(USE_DEBUG)) { 3507 PetscInt dof; 3508 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3509 if (dof) { 3510 if (cone) PetscAssertPointer(cone, 3); 3511 if (ornt) PetscAssertPointer(ornt, 4); 3512 } 3513 } 3514 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3515 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3516 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3517 } 3518 PetscFunctionReturn(PETSC_SUCCESS); 3519 } 3520 3521 /*@C 3522 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3523 3524 Not Collective 3525 3526 Input Parameters: 3527 + dm - The DMPlex 3528 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 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 Fortran Notes: 3542 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3543 `DMPlexRestoreCone()` is not needed/available in C. 3544 3545 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3546 @*/ 3547 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3548 { 3549 DM_Plex *mesh = (DM_Plex *)dm->data; 3550 3551 PetscFunctionBegin; 3552 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3553 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3554 PetscFunctionReturn(PETSC_SUCCESS); 3555 } 3556 3557 /*@ 3558 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3559 3560 Not Collective 3561 3562 Input Parameters: 3563 + dm - The `DMPLEX` 3564 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3565 3566 Output Parameter: 3567 . size - The support size for point `p` 3568 3569 Level: beginner 3570 3571 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3572 @*/ 3573 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3574 { 3575 DM_Plex *mesh = (DM_Plex *)dm->data; 3576 3577 PetscFunctionBegin; 3578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3579 PetscAssertPointer(size, 3); 3580 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3581 PetscFunctionReturn(PETSC_SUCCESS); 3582 } 3583 3584 /*@ 3585 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3586 3587 Not Collective 3588 3589 Input Parameters: 3590 + dm - The `DMPLEX` 3591 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3592 - size - The support size for point `p` 3593 3594 Level: beginner 3595 3596 Note: 3597 This should be called after `DMPlexSetChart()`. 3598 3599 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3600 @*/ 3601 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3602 { 3603 DM_Plex *mesh = (DM_Plex *)dm->data; 3604 3605 PetscFunctionBegin; 3606 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3607 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3608 PetscFunctionReturn(PETSC_SUCCESS); 3609 } 3610 3611 /*@C 3612 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3613 3614 Not Collective 3615 3616 Input Parameters: 3617 + dm - The `DMPLEX` 3618 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3619 3620 Output Parameter: 3621 . support - An array of points which are on the out-edges for point `p` 3622 3623 Level: beginner 3624 3625 Fortran Notes: 3626 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3627 `DMPlexRestoreSupport()` is not needed/available in C. 3628 3629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3630 @*/ 3631 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3632 { 3633 DM_Plex *mesh = (DM_Plex *)dm->data; 3634 PetscInt off; 3635 3636 PetscFunctionBegin; 3637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3638 PetscAssertPointer(support, 3); 3639 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3640 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3641 PetscFunctionReturn(PETSC_SUCCESS); 3642 } 3643 3644 /*@ 3645 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3646 3647 Not Collective 3648 3649 Input Parameters: 3650 + dm - The `DMPLEX` 3651 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3652 - support - An array of points which are on the out-edges for point `p` 3653 3654 Level: beginner 3655 3656 Note: 3657 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3658 3659 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3660 @*/ 3661 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3662 { 3663 DM_Plex *mesh = (DM_Plex *)dm->data; 3664 PetscInt pStart, pEnd; 3665 PetscInt dof, off, c; 3666 3667 PetscFunctionBegin; 3668 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3669 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3670 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3671 if (dof) PetscAssertPointer(support, 3); 3672 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3673 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); 3674 for (c = 0; c < dof; ++c) { 3675 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); 3676 mesh->supports[off + c] = support[c]; 3677 } 3678 PetscFunctionReturn(PETSC_SUCCESS); 3679 } 3680 3681 /*@ 3682 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3683 3684 Not Collective 3685 3686 Input Parameters: 3687 + dm - The `DMPLEX` 3688 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3689 . supportPos - The local index in the cone where the point should be put 3690 - supportPoint - The mesh point to insert 3691 3692 Level: beginner 3693 3694 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3695 @*/ 3696 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3697 { 3698 DM_Plex *mesh = (DM_Plex *)dm->data; 3699 PetscInt pStart, pEnd; 3700 PetscInt dof, off; 3701 3702 PetscFunctionBegin; 3703 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3704 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3705 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3706 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3707 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); 3708 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); 3709 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); 3710 mesh->supports[off + supportPos] = supportPoint; 3711 PetscFunctionReturn(PETSC_SUCCESS); 3712 } 3713 3714 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3715 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3716 { 3717 switch (ct) { 3718 case DM_POLYTOPE_SEGMENT: 3719 if (o == -1) return -2; 3720 break; 3721 case DM_POLYTOPE_TRIANGLE: 3722 if (o == -3) return -1; 3723 if (o == -2) return -3; 3724 if (o == -1) return -2; 3725 break; 3726 case DM_POLYTOPE_QUADRILATERAL: 3727 if (o == -4) return -2; 3728 if (o == -3) return -1; 3729 if (o == -2) return -4; 3730 if (o == -1) return -3; 3731 break; 3732 default: 3733 return o; 3734 } 3735 return o; 3736 } 3737 3738 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3739 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3740 { 3741 switch (ct) { 3742 case DM_POLYTOPE_SEGMENT: 3743 if ((o == -2) || (o == 1)) return -1; 3744 if (o == -1) return 0; 3745 break; 3746 case DM_POLYTOPE_TRIANGLE: 3747 if (o == -3) return -2; 3748 if (o == -2) return -1; 3749 if (o == -1) return -3; 3750 break; 3751 case DM_POLYTOPE_QUADRILATERAL: 3752 if (o == -4) return -2; 3753 if (o == -3) return -1; 3754 if (o == -2) return -4; 3755 if (o == -1) return -3; 3756 break; 3757 default: 3758 return o; 3759 } 3760 return o; 3761 } 3762 3763 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3764 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3765 { 3766 PetscInt pStart, pEnd, p; 3767 3768 PetscFunctionBegin; 3769 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3770 for (p = pStart; p < pEnd; ++p) { 3771 const PetscInt *cone, *ornt; 3772 PetscInt coneSize, c; 3773 3774 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3775 PetscCall(DMPlexGetCone(dm, p, &cone)); 3776 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3777 for (c = 0; c < coneSize; ++c) { 3778 DMPolytopeType ct; 3779 const PetscInt o = ornt[c]; 3780 3781 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3782 switch (ct) { 3783 case DM_POLYTOPE_SEGMENT: 3784 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3785 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3786 break; 3787 case DM_POLYTOPE_TRIANGLE: 3788 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3789 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3790 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3791 break; 3792 case DM_POLYTOPE_QUADRILATERAL: 3793 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3794 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3795 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3796 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3797 break; 3798 default: 3799 break; 3800 } 3801 } 3802 } 3803 PetscFunctionReturn(PETSC_SUCCESS); 3804 } 3805 3806 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3807 { 3808 DM_Plex *mesh = (DM_Plex *)dm->data; 3809 3810 PetscFunctionBeginHot; 3811 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3812 if (useCone) { 3813 PetscCall(DMPlexGetConeSize(dm, p, size)); 3814 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3815 } else { 3816 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3817 PetscCall(DMPlexGetSupport(dm, p, arr)); 3818 } 3819 } else { 3820 if (useCone) { 3821 const PetscSection s = mesh->coneSection; 3822 const PetscInt ps = p - s->pStart; 3823 const PetscInt off = s->atlasOff[ps]; 3824 3825 *size = s->atlasDof[ps]; 3826 *arr = mesh->cones + off; 3827 *ornt = mesh->coneOrientations + off; 3828 } else { 3829 const PetscSection s = mesh->supportSection; 3830 const PetscInt ps = p - s->pStart; 3831 const PetscInt off = s->atlasOff[ps]; 3832 3833 *size = s->atlasDof[ps]; 3834 *arr = mesh->supports + off; 3835 } 3836 } 3837 PetscFunctionReturn(PETSC_SUCCESS); 3838 } 3839 3840 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3841 { 3842 DM_Plex *mesh = (DM_Plex *)dm->data; 3843 3844 PetscFunctionBeginHot; 3845 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3846 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3847 } 3848 PetscFunctionReturn(PETSC_SUCCESS); 3849 } 3850 3851 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3852 { 3853 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3854 PetscInt *closure; 3855 const PetscInt *tmp = NULL, *tmpO = NULL; 3856 PetscInt off = 0, tmpSize, t; 3857 3858 PetscFunctionBeginHot; 3859 if (ornt) { 3860 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3861 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; 3862 } 3863 if (*points) { 3864 closure = *points; 3865 } else { 3866 PetscInt maxConeSize, maxSupportSize; 3867 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3868 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3869 } 3870 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3871 if (ct == DM_POLYTOPE_UNKNOWN) { 3872 closure[off++] = p; 3873 closure[off++] = 0; 3874 for (t = 0; t < tmpSize; ++t) { 3875 closure[off++] = tmp[t]; 3876 closure[off++] = tmpO ? tmpO[t] : 0; 3877 } 3878 } else { 3879 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3880 3881 /* We assume that cells with a valid type have faces with a valid type */ 3882 closure[off++] = p; 3883 closure[off++] = ornt; 3884 for (t = 0; t < tmpSize; ++t) { 3885 DMPolytopeType ft; 3886 3887 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3888 closure[off++] = tmp[arr[t]]; 3889 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3890 } 3891 } 3892 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3893 if (numPoints) *numPoints = tmpSize + 1; 3894 if (points) *points = closure; 3895 PetscFunctionReturn(PETSC_SUCCESS); 3896 } 3897 3898 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3899 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3900 { 3901 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3902 const PetscInt *cone, *ornt; 3903 PetscInt *pts, *closure = NULL; 3904 DMPolytopeType ft; 3905 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3906 PetscInt dim, coneSize, c, d, clSize, cl; 3907 3908 PetscFunctionBeginHot; 3909 PetscCall(DMGetDimension(dm, &dim)); 3910 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3911 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3912 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3913 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3914 maxSize = PetscMax(coneSeries, supportSeries); 3915 if (*points) { 3916 pts = *points; 3917 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3918 c = 0; 3919 pts[c++] = point; 3920 pts[c++] = o; 3921 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3922 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3923 for (cl = 0; cl < clSize * 2; cl += 2) { 3924 pts[c++] = closure[cl]; 3925 pts[c++] = closure[cl + 1]; 3926 } 3927 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3928 for (cl = 0; cl < clSize * 2; cl += 2) { 3929 pts[c++] = closure[cl]; 3930 pts[c++] = closure[cl + 1]; 3931 } 3932 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3933 for (d = 2; d < coneSize; ++d) { 3934 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3935 pts[c++] = cone[arr[d * 2 + 0]]; 3936 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3937 } 3938 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3939 if (dim >= 3) { 3940 for (d = 2; d < coneSize; ++d) { 3941 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3942 const PetscInt *fcone, *fornt; 3943 PetscInt fconeSize, fc, i; 3944 3945 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3946 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3947 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3948 for (fc = 0; fc < fconeSize; ++fc) { 3949 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3950 const PetscInt co = farr[fc * 2 + 1]; 3951 3952 for (i = 0; i < c; i += 2) 3953 if (pts[i] == cp) break; 3954 if (i == c) { 3955 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3956 pts[c++] = cp; 3957 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3958 } 3959 } 3960 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3961 } 3962 } 3963 *numPoints = c / 2; 3964 *points = pts; 3965 PetscFunctionReturn(PETSC_SUCCESS); 3966 } 3967 3968 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3969 { 3970 DMPolytopeType ct; 3971 PetscInt *closure, *fifo; 3972 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3973 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3974 PetscInt depth, maxSize; 3975 3976 PetscFunctionBeginHot; 3977 PetscCall(DMPlexGetDepth(dm, &depth)); 3978 if (depth == 1) { 3979 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3980 PetscFunctionReturn(PETSC_SUCCESS); 3981 } 3982 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3983 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; 3984 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3985 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3986 PetscFunctionReturn(PETSC_SUCCESS); 3987 } 3988 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3989 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3990 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3991 maxSize = PetscMax(coneSeries, supportSeries); 3992 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3993 if (*points) { 3994 closure = *points; 3995 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3996 closure[closureSize++] = p; 3997 closure[closureSize++] = ornt; 3998 fifo[fifoSize++] = p; 3999 fifo[fifoSize++] = ornt; 4000 fifo[fifoSize++] = ct; 4001 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4002 while (fifoSize - fifoStart) { 4003 const PetscInt q = fifo[fifoStart++]; 4004 const PetscInt o = fifo[fifoStart++]; 4005 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4006 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4007 const PetscInt *tmp, *tmpO = NULL; 4008 PetscInt tmpSize, t; 4009 4010 if (PetscDefined(USE_DEBUG)) { 4011 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4012 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); 4013 } 4014 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4015 for (t = 0; t < tmpSize; ++t) { 4016 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4017 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4018 const PetscInt cp = tmp[ip]; 4019 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4020 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4021 PetscInt c; 4022 4023 /* Check for duplicate */ 4024 for (c = 0; c < closureSize; c += 2) { 4025 if (closure[c] == cp) break; 4026 } 4027 if (c == closureSize) { 4028 closure[closureSize++] = cp; 4029 closure[closureSize++] = co; 4030 fifo[fifoSize++] = cp; 4031 fifo[fifoSize++] = co; 4032 fifo[fifoSize++] = ct; 4033 } 4034 } 4035 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4036 } 4037 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4038 if (numPoints) *numPoints = closureSize / 2; 4039 if (points) *points = closure; 4040 PetscFunctionReturn(PETSC_SUCCESS); 4041 } 4042 4043 /*@C 4044 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4045 4046 Not Collective 4047 4048 Input Parameters: 4049 + dm - The `DMPLEX` 4050 . p - The mesh point 4051 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4052 4053 Input/Output Parameter: 4054 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4055 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4056 4057 Output Parameter: 4058 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4059 4060 Level: beginner 4061 4062 Note: 4063 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4064 4065 Fortran Notes: 4066 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4067 4068 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4069 @*/ 4070 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4071 { 4072 PetscFunctionBeginHot; 4073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4074 if (numPoints) PetscAssertPointer(numPoints, 4); 4075 if (points) PetscAssertPointer(points, 5); 4076 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4077 PetscFunctionReturn(PETSC_SUCCESS); 4078 } 4079 4080 /*@C 4081 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4082 4083 Not Collective 4084 4085 Input Parameters: 4086 + dm - The `DMPLEX` 4087 . p - The mesh point 4088 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4089 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4090 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4091 4092 Level: beginner 4093 4094 Note: 4095 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4096 4097 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4098 @*/ 4099 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4100 { 4101 PetscFunctionBeginHot; 4102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4103 if (numPoints) *numPoints = 0; 4104 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4105 PetscFunctionReturn(PETSC_SUCCESS); 4106 } 4107 4108 /*@ 4109 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4110 4111 Not Collective 4112 4113 Input Parameter: 4114 . dm - The `DMPLEX` 4115 4116 Output Parameters: 4117 + maxConeSize - The maximum number of in-edges 4118 - maxSupportSize - The maximum number of out-edges 4119 4120 Level: beginner 4121 4122 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4123 @*/ 4124 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4125 { 4126 DM_Plex *mesh = (DM_Plex *)dm->data; 4127 4128 PetscFunctionBegin; 4129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4130 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4131 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4132 PetscFunctionReturn(PETSC_SUCCESS); 4133 } 4134 4135 PetscErrorCode DMSetUp_Plex(DM dm) 4136 { 4137 DM_Plex *mesh = (DM_Plex *)dm->data; 4138 PetscInt size, maxSupportSize; 4139 4140 PetscFunctionBegin; 4141 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4142 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4143 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4144 PetscCall(PetscMalloc1(size, &mesh->cones)); 4145 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4146 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4147 if (maxSupportSize) { 4148 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4149 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4150 PetscCall(PetscMalloc1(size, &mesh->supports)); 4151 } 4152 PetscFunctionReturn(PETSC_SUCCESS); 4153 } 4154 4155 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4156 { 4157 PetscFunctionBegin; 4158 if (subdm) PetscCall(DMClone(dm, subdm)); 4159 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4160 if (subdm) (*subdm)->useNatural = dm->useNatural; 4161 if (dm->useNatural && dm->sfMigration) { 4162 PetscSF sfNatural; 4163 4164 (*subdm)->sfMigration = dm->sfMigration; 4165 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4166 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4167 (*subdm)->sfNatural = sfNatural; 4168 } 4169 PetscFunctionReturn(PETSC_SUCCESS); 4170 } 4171 4172 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4173 { 4174 PetscInt i = 0; 4175 4176 PetscFunctionBegin; 4177 PetscCall(DMClone(dms[0], superdm)); 4178 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4179 (*superdm)->useNatural = PETSC_FALSE; 4180 for (i = 0; i < len; i++) { 4181 if (dms[i]->useNatural && dms[i]->sfMigration) { 4182 PetscSF sfNatural; 4183 4184 (*superdm)->sfMigration = dms[i]->sfMigration; 4185 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4186 (*superdm)->useNatural = PETSC_TRUE; 4187 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4188 (*superdm)->sfNatural = sfNatural; 4189 break; 4190 } 4191 } 4192 PetscFunctionReturn(PETSC_SUCCESS); 4193 } 4194 4195 /*@ 4196 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4197 4198 Not Collective 4199 4200 Input Parameter: 4201 . dm - The `DMPLEX` 4202 4203 Level: beginner 4204 4205 Note: 4206 This should be called after all calls to `DMPlexSetCone()` 4207 4208 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4209 @*/ 4210 PetscErrorCode DMPlexSymmetrize(DM dm) 4211 { 4212 DM_Plex *mesh = (DM_Plex *)dm->data; 4213 PetscInt *offsets; 4214 PetscInt supportSize; 4215 PetscInt pStart, pEnd, p; 4216 4217 PetscFunctionBegin; 4218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4219 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4220 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4221 /* Calculate support sizes */ 4222 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4223 for (p = pStart; p < pEnd; ++p) { 4224 PetscInt dof, off, c; 4225 4226 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4227 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4228 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4229 } 4230 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4231 /* Calculate supports */ 4232 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4233 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4234 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4235 for (p = pStart; p < pEnd; ++p) { 4236 PetscInt dof, off, c; 4237 4238 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4239 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4240 for (c = off; c < off + dof; ++c) { 4241 const PetscInt q = mesh->cones[c]; 4242 PetscInt offS; 4243 4244 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4245 4246 mesh->supports[offS + offsets[q]] = p; 4247 ++offsets[q]; 4248 } 4249 } 4250 PetscCall(PetscFree(offsets)); 4251 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4252 PetscFunctionReturn(PETSC_SUCCESS); 4253 } 4254 4255 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4256 { 4257 IS stratumIS; 4258 4259 PetscFunctionBegin; 4260 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4261 if (PetscDefined(USE_DEBUG)) { 4262 PetscInt qStart, qEnd, numLevels, level; 4263 PetscBool overlap = PETSC_FALSE; 4264 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4265 for (level = 0; level < numLevels; level++) { 4266 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4267 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4268 overlap = PETSC_TRUE; 4269 break; 4270 } 4271 } 4272 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); 4273 } 4274 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4275 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4276 PetscCall(ISDestroy(&stratumIS)); 4277 PetscFunctionReturn(PETSC_SUCCESS); 4278 } 4279 4280 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4281 { 4282 PetscInt *pMin, *pMax; 4283 PetscInt pStart, pEnd; 4284 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4285 4286 PetscFunctionBegin; 4287 { 4288 DMLabel label2; 4289 4290 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4291 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4292 } 4293 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4294 for (PetscInt p = pStart; p < pEnd; ++p) { 4295 DMPolytopeType ct; 4296 4297 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4298 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4299 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4300 } 4301 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4302 for (PetscInt d = dmin; d <= dmax; ++d) { 4303 pMin[d] = PETSC_MAX_INT; 4304 pMax[d] = PETSC_MIN_INT; 4305 } 4306 for (PetscInt p = pStart; p < pEnd; ++p) { 4307 DMPolytopeType ct; 4308 PetscInt d; 4309 4310 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4311 d = DMPolytopeTypeGetDim(ct); 4312 pMin[d] = PetscMin(p, pMin[d]); 4313 pMax[d] = PetscMax(p, pMax[d]); 4314 } 4315 for (PetscInt d = dmin; d <= dmax; ++d) { 4316 if (pMin[d] > pMax[d]) continue; 4317 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4318 } 4319 PetscCall(PetscFree2(pMin, pMax)); 4320 PetscFunctionReturn(PETSC_SUCCESS); 4321 } 4322 4323 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4324 { 4325 PetscInt pStart, pEnd; 4326 PetscInt numRoots = 0, numLeaves = 0; 4327 4328 PetscFunctionBegin; 4329 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4330 { 4331 /* Initialize roots and count leaves */ 4332 PetscInt sMin = PETSC_MAX_INT; 4333 PetscInt sMax = PETSC_MIN_INT; 4334 PetscInt coneSize, supportSize; 4335 4336 for (PetscInt p = pStart; p < pEnd; ++p) { 4337 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4338 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4339 if (!coneSize && supportSize) { 4340 sMin = PetscMin(p, sMin); 4341 sMax = PetscMax(p, sMax); 4342 ++numRoots; 4343 } else if (!supportSize && coneSize) { 4344 ++numLeaves; 4345 } else if (!supportSize && !coneSize) { 4346 /* Isolated points */ 4347 sMin = PetscMin(p, sMin); 4348 sMax = PetscMax(p, sMax); 4349 } 4350 } 4351 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4352 } 4353 4354 if (numRoots + numLeaves == (pEnd - pStart)) { 4355 PetscInt sMin = PETSC_MAX_INT; 4356 PetscInt sMax = PETSC_MIN_INT; 4357 PetscInt coneSize, supportSize; 4358 4359 for (PetscInt p = pStart; p < pEnd; ++p) { 4360 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4361 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4362 if (!supportSize && coneSize) { 4363 sMin = PetscMin(p, sMin); 4364 sMax = PetscMax(p, sMax); 4365 } 4366 } 4367 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4368 } else { 4369 PetscInt level = 0; 4370 PetscInt qStart, qEnd; 4371 4372 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4373 while (qEnd > qStart) { 4374 PetscInt sMin = PETSC_MAX_INT; 4375 PetscInt sMax = PETSC_MIN_INT; 4376 4377 for (PetscInt q = qStart; q < qEnd; ++q) { 4378 const PetscInt *support; 4379 PetscInt supportSize; 4380 4381 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4382 PetscCall(DMPlexGetSupport(dm, q, &support)); 4383 for (PetscInt s = 0; s < supportSize; ++s) { 4384 sMin = PetscMin(support[s], sMin); 4385 sMax = PetscMax(support[s], sMax); 4386 } 4387 } 4388 PetscCall(DMLabelGetNumValues(label, &level)); 4389 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4390 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4391 } 4392 } 4393 PetscFunctionReturn(PETSC_SUCCESS); 4394 } 4395 4396 /*@ 4397 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4398 4399 Collective 4400 4401 Input Parameter: 4402 . dm - The `DMPLEX` 4403 4404 Level: beginner 4405 4406 Notes: 4407 The strata group all points of the same grade, and this function calculates the strata. This 4408 grade can be seen as the height (or depth) of the point in the DAG. 4409 4410 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4411 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4412 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4413 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4414 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4415 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4416 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4417 4418 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4419 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4420 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 4421 to interpolate only that one (e0), so that 4422 .vb 4423 cone(c0) = {e0, v2} 4424 cone(e0) = {v0, v1} 4425 .ve 4426 If `DMPlexStratify()` is run on this mesh, it will give depths 4427 .vb 4428 depth 0 = {v0, v1, v2} 4429 depth 1 = {e0, c0} 4430 .ve 4431 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4432 4433 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4434 4435 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4436 @*/ 4437 PetscErrorCode DMPlexStratify(DM dm) 4438 { 4439 DM_Plex *mesh = (DM_Plex *)dm->data; 4440 DMLabel label; 4441 PetscBool flg = PETSC_FALSE; 4442 4443 PetscFunctionBegin; 4444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4445 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4446 4447 // Create depth label 4448 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4449 PetscCall(DMCreateLabel(dm, "depth")); 4450 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4451 4452 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4453 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4454 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4455 4456 { /* just in case there is an empty process */ 4457 PetscInt numValues, maxValues = 0, v; 4458 4459 PetscCall(DMLabelGetNumValues(label, &numValues)); 4460 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4461 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4462 } 4463 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4464 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4465 PetscFunctionReturn(PETSC_SUCCESS); 4466 } 4467 4468 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4469 { 4470 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4471 PetscInt dim, depth, pheight, coneSize; 4472 4473 PetscFunctionBeginHot; 4474 PetscCall(DMGetDimension(dm, &dim)); 4475 PetscCall(DMPlexGetDepth(dm, &depth)); 4476 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4477 pheight = depth - pdepth; 4478 if (depth <= 1) { 4479 switch (pdepth) { 4480 case 0: 4481 ct = DM_POLYTOPE_POINT; 4482 break; 4483 case 1: 4484 switch (coneSize) { 4485 case 2: 4486 ct = DM_POLYTOPE_SEGMENT; 4487 break; 4488 case 3: 4489 ct = DM_POLYTOPE_TRIANGLE; 4490 break; 4491 case 4: 4492 switch (dim) { 4493 case 2: 4494 ct = DM_POLYTOPE_QUADRILATERAL; 4495 break; 4496 case 3: 4497 ct = DM_POLYTOPE_TETRAHEDRON; 4498 break; 4499 default: 4500 break; 4501 } 4502 break; 4503 case 5: 4504 ct = DM_POLYTOPE_PYRAMID; 4505 break; 4506 case 6: 4507 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4508 break; 4509 case 8: 4510 ct = DM_POLYTOPE_HEXAHEDRON; 4511 break; 4512 default: 4513 break; 4514 } 4515 } 4516 } else { 4517 if (pdepth == 0) { 4518 ct = DM_POLYTOPE_POINT; 4519 } else if (pheight == 0) { 4520 switch (dim) { 4521 case 1: 4522 switch (coneSize) { 4523 case 2: 4524 ct = DM_POLYTOPE_SEGMENT; 4525 break; 4526 default: 4527 break; 4528 } 4529 break; 4530 case 2: 4531 switch (coneSize) { 4532 case 3: 4533 ct = DM_POLYTOPE_TRIANGLE; 4534 break; 4535 case 4: 4536 ct = DM_POLYTOPE_QUADRILATERAL; 4537 break; 4538 default: 4539 break; 4540 } 4541 break; 4542 case 3: 4543 switch (coneSize) { 4544 case 4: 4545 ct = DM_POLYTOPE_TETRAHEDRON; 4546 break; 4547 case 5: { 4548 const PetscInt *cone; 4549 PetscInt faceConeSize; 4550 4551 PetscCall(DMPlexGetCone(dm, p, &cone)); 4552 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4553 switch (faceConeSize) { 4554 case 3: 4555 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4556 break; 4557 case 4: 4558 ct = DM_POLYTOPE_PYRAMID; 4559 break; 4560 } 4561 } break; 4562 case 6: 4563 ct = DM_POLYTOPE_HEXAHEDRON; 4564 break; 4565 default: 4566 break; 4567 } 4568 break; 4569 default: 4570 break; 4571 } 4572 } else if (pheight > 0) { 4573 switch (coneSize) { 4574 case 2: 4575 ct = DM_POLYTOPE_SEGMENT; 4576 break; 4577 case 3: 4578 ct = DM_POLYTOPE_TRIANGLE; 4579 break; 4580 case 4: 4581 ct = DM_POLYTOPE_QUADRILATERAL; 4582 break; 4583 default: 4584 break; 4585 } 4586 } 4587 } 4588 *pt = ct; 4589 PetscFunctionReturn(PETSC_SUCCESS); 4590 } 4591 4592 /*@ 4593 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4594 4595 Collective 4596 4597 Input Parameter: 4598 . dm - The `DMPLEX` 4599 4600 Level: developer 4601 4602 Note: 4603 This function is normally called automatically when a cell type is requested. It creates an 4604 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4605 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4606 4607 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4608 4609 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4610 @*/ 4611 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4612 { 4613 DM_Plex *mesh; 4614 DMLabel ctLabel; 4615 PetscInt pStart, pEnd, p; 4616 4617 PetscFunctionBegin; 4618 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4619 mesh = (DM_Plex *)dm->data; 4620 PetscCall(DMCreateLabel(dm, "celltype")); 4621 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4622 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4623 PetscCall(PetscFree(mesh->cellTypes)); 4624 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4625 for (p = pStart; p < pEnd; ++p) { 4626 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4627 PetscInt pdepth; 4628 4629 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4630 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4631 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4632 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4633 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4634 } 4635 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4636 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4637 PetscFunctionReturn(PETSC_SUCCESS); 4638 } 4639 4640 /*@C 4641 DMPlexGetJoin - Get an array for the join of the set of points 4642 4643 Not Collective 4644 4645 Input Parameters: 4646 + dm - The `DMPLEX` object 4647 . numPoints - The number of input points for the join 4648 - points - The input points 4649 4650 Output Parameters: 4651 + numCoveredPoints - The number of points in the join 4652 - coveredPoints - The points in the join 4653 4654 Level: intermediate 4655 4656 Note: 4657 Currently, this is restricted to a single level join 4658 4659 Fortran Notes: 4660 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4661 4662 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4663 @*/ 4664 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4665 { 4666 DM_Plex *mesh = (DM_Plex *)dm->data; 4667 PetscInt *join[2]; 4668 PetscInt joinSize, i = 0; 4669 PetscInt dof, off, p, c, m; 4670 PetscInt maxSupportSize; 4671 4672 PetscFunctionBegin; 4673 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4674 PetscAssertPointer(points, 3); 4675 PetscAssertPointer(numCoveredPoints, 4); 4676 PetscAssertPointer(coveredPoints, 5); 4677 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4678 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4679 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4680 /* Copy in support of first point */ 4681 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4682 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4683 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4684 /* Check each successive support */ 4685 for (p = 1; p < numPoints; ++p) { 4686 PetscInt newJoinSize = 0; 4687 4688 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4689 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4690 for (c = 0; c < dof; ++c) { 4691 const PetscInt point = mesh->supports[off + c]; 4692 4693 for (m = 0; m < joinSize; ++m) { 4694 if (point == join[i][m]) { 4695 join[1 - i][newJoinSize++] = point; 4696 break; 4697 } 4698 } 4699 } 4700 joinSize = newJoinSize; 4701 i = 1 - i; 4702 } 4703 *numCoveredPoints = joinSize; 4704 *coveredPoints = join[i]; 4705 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4706 PetscFunctionReturn(PETSC_SUCCESS); 4707 } 4708 4709 /*@C 4710 DMPlexRestoreJoin - Restore an array for the join of the set of points 4711 4712 Not Collective 4713 4714 Input Parameters: 4715 + dm - The `DMPLEX` object 4716 . numPoints - The number of input points for the join 4717 - points - The input points 4718 4719 Output Parameters: 4720 + numCoveredPoints - The number of points in the join 4721 - coveredPoints - The points in the join 4722 4723 Level: intermediate 4724 4725 Fortran Notes: 4726 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4727 4728 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4729 @*/ 4730 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4731 { 4732 PetscFunctionBegin; 4733 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4734 if (points) PetscAssertPointer(points, 3); 4735 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4736 PetscAssertPointer(coveredPoints, 5); 4737 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4738 if (numCoveredPoints) *numCoveredPoints = 0; 4739 PetscFunctionReturn(PETSC_SUCCESS); 4740 } 4741 4742 /*@C 4743 DMPlexGetFullJoin - Get an array for the join of the set of points 4744 4745 Not Collective 4746 4747 Input Parameters: 4748 + dm - The `DMPLEX` object 4749 . numPoints - The number of input points for the join 4750 - points - The input points 4751 4752 Output Parameters: 4753 + numCoveredPoints - The number of points in the join 4754 - coveredPoints - The points in the join 4755 4756 Level: intermediate 4757 4758 Fortran Notes: 4759 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4760 4761 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4762 @*/ 4763 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4764 { 4765 PetscInt *offsets, **closures; 4766 PetscInt *join[2]; 4767 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4768 PetscInt p, d, c, m, ms; 4769 4770 PetscFunctionBegin; 4771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4772 PetscAssertPointer(points, 3); 4773 PetscAssertPointer(numCoveredPoints, 4); 4774 PetscAssertPointer(coveredPoints, 5); 4775 4776 PetscCall(DMPlexGetDepth(dm, &depth)); 4777 PetscCall(PetscCalloc1(numPoints, &closures)); 4778 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4779 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4780 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4781 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4782 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4783 4784 for (p = 0; p < numPoints; ++p) { 4785 PetscInt closureSize; 4786 4787 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4788 4789 offsets[p * (depth + 2) + 0] = 0; 4790 for (d = 0; d < depth + 1; ++d) { 4791 PetscInt pStart, pEnd, i; 4792 4793 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4794 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4795 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4796 offsets[p * (depth + 2) + d + 1] = i; 4797 break; 4798 } 4799 } 4800 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4801 } 4802 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); 4803 } 4804 for (d = 0; d < depth + 1; ++d) { 4805 PetscInt dof; 4806 4807 /* Copy in support of first point */ 4808 dof = offsets[d + 1] - offsets[d]; 4809 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4810 /* Check each successive cone */ 4811 for (p = 1; p < numPoints && joinSize; ++p) { 4812 PetscInt newJoinSize = 0; 4813 4814 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4815 for (c = 0; c < dof; ++c) { 4816 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4817 4818 for (m = 0; m < joinSize; ++m) { 4819 if (point == join[i][m]) { 4820 join[1 - i][newJoinSize++] = point; 4821 break; 4822 } 4823 } 4824 } 4825 joinSize = newJoinSize; 4826 i = 1 - i; 4827 } 4828 if (joinSize) break; 4829 } 4830 *numCoveredPoints = joinSize; 4831 *coveredPoints = join[i]; 4832 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4833 PetscCall(PetscFree(closures)); 4834 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4835 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4836 PetscFunctionReturn(PETSC_SUCCESS); 4837 } 4838 4839 /*@C 4840 DMPlexGetMeet - Get an array for the meet of the set of points 4841 4842 Not Collective 4843 4844 Input Parameters: 4845 + dm - The `DMPLEX` object 4846 . numPoints - The number of input points for the meet 4847 - points - The input points 4848 4849 Output Parameters: 4850 + numCoveringPoints - The number of points in the meet 4851 - coveringPoints - The points in the meet 4852 4853 Level: intermediate 4854 4855 Note: 4856 Currently, this is restricted to a single level meet 4857 4858 Fortran Notes: 4859 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4860 4861 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4862 @*/ 4863 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4864 { 4865 DM_Plex *mesh = (DM_Plex *)dm->data; 4866 PetscInt *meet[2]; 4867 PetscInt meetSize, i = 0; 4868 PetscInt dof, off, p, c, m; 4869 PetscInt maxConeSize; 4870 4871 PetscFunctionBegin; 4872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4873 PetscAssertPointer(points, 3); 4874 PetscAssertPointer(numCoveringPoints, 4); 4875 PetscAssertPointer(coveringPoints, 5); 4876 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4877 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4878 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4879 /* Copy in cone of first point */ 4880 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4881 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4882 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4883 /* Check each successive cone */ 4884 for (p = 1; p < numPoints; ++p) { 4885 PetscInt newMeetSize = 0; 4886 4887 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4888 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4889 for (c = 0; c < dof; ++c) { 4890 const PetscInt point = mesh->cones[off + c]; 4891 4892 for (m = 0; m < meetSize; ++m) { 4893 if (point == meet[i][m]) { 4894 meet[1 - i][newMeetSize++] = point; 4895 break; 4896 } 4897 } 4898 } 4899 meetSize = newMeetSize; 4900 i = 1 - i; 4901 } 4902 *numCoveringPoints = meetSize; 4903 *coveringPoints = meet[i]; 4904 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4905 PetscFunctionReturn(PETSC_SUCCESS); 4906 } 4907 4908 /*@C 4909 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4910 4911 Not Collective 4912 4913 Input Parameters: 4914 + dm - The `DMPLEX` object 4915 . numPoints - The number of input points for the meet 4916 - points - The input points 4917 4918 Output Parameters: 4919 + numCoveredPoints - The number of points in the meet 4920 - coveredPoints - The points in the meet 4921 4922 Level: intermediate 4923 4924 Fortran Notes: 4925 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4926 4927 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4928 @*/ 4929 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4930 { 4931 PetscFunctionBegin; 4932 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4933 if (points) PetscAssertPointer(points, 3); 4934 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4935 PetscAssertPointer(coveredPoints, 5); 4936 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4937 if (numCoveredPoints) *numCoveredPoints = 0; 4938 PetscFunctionReturn(PETSC_SUCCESS); 4939 } 4940 4941 /*@C 4942 DMPlexGetFullMeet - Get an array for the meet of the set of points 4943 4944 Not Collective 4945 4946 Input Parameters: 4947 + dm - The `DMPLEX` object 4948 . numPoints - The number of input points for the meet 4949 - points - The input points 4950 4951 Output Parameters: 4952 + numCoveredPoints - The number of points in the meet 4953 - coveredPoints - The points in the meet 4954 4955 Level: intermediate 4956 4957 Fortran Notes: 4958 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4959 4960 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4961 @*/ 4962 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4963 { 4964 PetscInt *offsets, **closures; 4965 PetscInt *meet[2]; 4966 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4967 PetscInt p, h, c, m, mc; 4968 4969 PetscFunctionBegin; 4970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4971 PetscAssertPointer(points, 3); 4972 PetscAssertPointer(numCoveredPoints, 4); 4973 PetscAssertPointer(coveredPoints, 5); 4974 4975 PetscCall(DMPlexGetDepth(dm, &height)); 4976 PetscCall(PetscMalloc1(numPoints, &closures)); 4977 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4978 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4979 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4980 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4981 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4982 4983 for (p = 0; p < numPoints; ++p) { 4984 PetscInt closureSize; 4985 4986 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4987 4988 offsets[p * (height + 2) + 0] = 0; 4989 for (h = 0; h < height + 1; ++h) { 4990 PetscInt pStart, pEnd, i; 4991 4992 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4993 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4994 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4995 offsets[p * (height + 2) + h + 1] = i; 4996 break; 4997 } 4998 } 4999 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5000 } 5001 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); 5002 } 5003 for (h = 0; h < height + 1; ++h) { 5004 PetscInt dof; 5005 5006 /* Copy in cone of first point */ 5007 dof = offsets[h + 1] - offsets[h]; 5008 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5009 /* Check each successive cone */ 5010 for (p = 1; p < numPoints && meetSize; ++p) { 5011 PetscInt newMeetSize = 0; 5012 5013 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5014 for (c = 0; c < dof; ++c) { 5015 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5016 5017 for (m = 0; m < meetSize; ++m) { 5018 if (point == meet[i][m]) { 5019 meet[1 - i][newMeetSize++] = point; 5020 break; 5021 } 5022 } 5023 } 5024 meetSize = newMeetSize; 5025 i = 1 - i; 5026 } 5027 if (meetSize) break; 5028 } 5029 *numCoveredPoints = meetSize; 5030 *coveredPoints = meet[i]; 5031 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5032 PetscCall(PetscFree(closures)); 5033 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5034 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5035 PetscFunctionReturn(PETSC_SUCCESS); 5036 } 5037 5038 /*@C 5039 DMPlexEqual - Determine if two `DM` have the same topology 5040 5041 Not Collective 5042 5043 Input Parameters: 5044 + dmA - A `DMPLEX` object 5045 - dmB - A `DMPLEX` object 5046 5047 Output Parameter: 5048 . equal - `PETSC_TRUE` if the topologies are identical 5049 5050 Level: intermediate 5051 5052 Note: 5053 We are not solving graph isomorphism, so we do not permute. 5054 5055 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5056 @*/ 5057 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5058 { 5059 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5060 5061 PetscFunctionBegin; 5062 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5063 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5064 PetscAssertPointer(equal, 3); 5065 5066 *equal = PETSC_FALSE; 5067 PetscCall(DMPlexGetDepth(dmA, &depth)); 5068 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5069 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5070 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5071 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5072 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5073 for (p = pStart; p < pEnd; ++p) { 5074 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5075 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5076 5077 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5078 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5079 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5080 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5081 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5082 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5083 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5084 for (c = 0; c < coneSize; ++c) { 5085 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5086 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5087 } 5088 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5089 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5090 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5091 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5092 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5093 for (s = 0; s < supportSize; ++s) { 5094 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5095 } 5096 } 5097 *equal = PETSC_TRUE; 5098 PetscFunctionReturn(PETSC_SUCCESS); 5099 } 5100 5101 /*@C 5102 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5103 5104 Not Collective 5105 5106 Input Parameters: 5107 + dm - The `DMPLEX` 5108 . cellDim - The cell dimension 5109 - numCorners - The number of vertices on a cell 5110 5111 Output Parameter: 5112 . numFaceVertices - The number of vertices on a face 5113 5114 Level: developer 5115 5116 Note: 5117 Of course this can only work for a restricted set of symmetric shapes 5118 5119 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5120 @*/ 5121 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5122 { 5123 MPI_Comm comm; 5124 5125 PetscFunctionBegin; 5126 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5127 PetscAssertPointer(numFaceVertices, 4); 5128 switch (cellDim) { 5129 case 0: 5130 *numFaceVertices = 0; 5131 break; 5132 case 1: 5133 *numFaceVertices = 1; 5134 break; 5135 case 2: 5136 switch (numCorners) { 5137 case 3: /* triangle */ 5138 *numFaceVertices = 2; /* Edge has 2 vertices */ 5139 break; 5140 case 4: /* quadrilateral */ 5141 *numFaceVertices = 2; /* Edge has 2 vertices */ 5142 break; 5143 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5144 *numFaceVertices = 3; /* Edge has 3 vertices */ 5145 break; 5146 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5147 *numFaceVertices = 3; /* Edge has 3 vertices */ 5148 break; 5149 default: 5150 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5151 } 5152 break; 5153 case 3: 5154 switch (numCorners) { 5155 case 4: /* tetradehdron */ 5156 *numFaceVertices = 3; /* Face has 3 vertices */ 5157 break; 5158 case 6: /* tet cohesive cells */ 5159 *numFaceVertices = 4; /* Face has 4 vertices */ 5160 break; 5161 case 8: /* hexahedron */ 5162 *numFaceVertices = 4; /* Face has 4 vertices */ 5163 break; 5164 case 9: /* tet cohesive Lagrange cells */ 5165 *numFaceVertices = 6; /* Face has 6 vertices */ 5166 break; 5167 case 10: /* quadratic tetrahedron */ 5168 *numFaceVertices = 6; /* Face has 6 vertices */ 5169 break; 5170 case 12: /* hex cohesive Lagrange cells */ 5171 *numFaceVertices = 6; /* Face has 6 vertices */ 5172 break; 5173 case 18: /* quadratic tet cohesive Lagrange cells */ 5174 *numFaceVertices = 6; /* Face has 6 vertices */ 5175 break; 5176 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5177 *numFaceVertices = 9; /* Face has 9 vertices */ 5178 break; 5179 default: 5180 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5181 } 5182 break; 5183 default: 5184 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5185 } 5186 PetscFunctionReturn(PETSC_SUCCESS); 5187 } 5188 5189 /*@ 5190 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5191 5192 Not Collective 5193 5194 Input Parameter: 5195 . dm - The `DMPLEX` object 5196 5197 Output Parameter: 5198 . depthLabel - The `DMLabel` recording point depth 5199 5200 Level: developer 5201 5202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5203 @*/ 5204 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5205 { 5206 PetscFunctionBegin; 5207 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5208 PetscAssertPointer(depthLabel, 2); 5209 *depthLabel = dm->depthLabel; 5210 PetscFunctionReturn(PETSC_SUCCESS); 5211 } 5212 5213 /*@ 5214 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5215 5216 Not Collective 5217 5218 Input Parameter: 5219 . dm - The `DMPLEX` object 5220 5221 Output Parameter: 5222 . depth - The number of strata (breadth first levels) in the DAG 5223 5224 Level: developer 5225 5226 Notes: 5227 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5228 5229 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5230 5231 An empty mesh gives -1. 5232 5233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5234 @*/ 5235 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5236 { 5237 DM_Plex *mesh = (DM_Plex *)dm->data; 5238 DMLabel label; 5239 PetscInt d = 0; 5240 5241 PetscFunctionBegin; 5242 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5243 PetscAssertPointer(depth, 2); 5244 if (mesh->tr) { 5245 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5246 } else { 5247 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5248 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5249 *depth = d - 1; 5250 } 5251 PetscFunctionReturn(PETSC_SUCCESS); 5252 } 5253 5254 /*@ 5255 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5256 5257 Not Collective 5258 5259 Input Parameters: 5260 + dm - The `DMPLEX` object 5261 - depth - The requested depth 5262 5263 Output Parameters: 5264 + start - The first point at this `depth` 5265 - end - One beyond the last point at this `depth` 5266 5267 Level: developer 5268 5269 Notes: 5270 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5271 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5272 higher dimension, e.g., "edges". 5273 5274 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5275 @*/ 5276 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5277 { 5278 DM_Plex *mesh = (DM_Plex *)dm->data; 5279 DMLabel label; 5280 PetscInt pStart, pEnd; 5281 5282 PetscFunctionBegin; 5283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5284 if (start) { 5285 PetscAssertPointer(start, 3); 5286 *start = 0; 5287 } 5288 if (end) { 5289 PetscAssertPointer(end, 4); 5290 *end = 0; 5291 } 5292 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5293 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5294 if (depth < 0) { 5295 if (start) *start = pStart; 5296 if (end) *end = pEnd; 5297 PetscFunctionReturn(PETSC_SUCCESS); 5298 } 5299 if (mesh->tr) { 5300 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5301 } else { 5302 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5303 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5304 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5305 } 5306 PetscFunctionReturn(PETSC_SUCCESS); 5307 } 5308 5309 /*@ 5310 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5311 5312 Not Collective 5313 5314 Input Parameters: 5315 + dm - The `DMPLEX` object 5316 - height - The requested height 5317 5318 Output Parameters: 5319 + start - The first point at this `height` 5320 - end - One beyond the last point at this `height` 5321 5322 Level: developer 5323 5324 Notes: 5325 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5326 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5327 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5328 5329 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5330 @*/ 5331 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5332 { 5333 DMLabel label; 5334 PetscInt depth, pStart, pEnd; 5335 5336 PetscFunctionBegin; 5337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5338 if (start) { 5339 PetscAssertPointer(start, 3); 5340 *start = 0; 5341 } 5342 if (end) { 5343 PetscAssertPointer(end, 4); 5344 *end = 0; 5345 } 5346 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5347 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5348 if (height < 0) { 5349 if (start) *start = pStart; 5350 if (end) *end = pEnd; 5351 PetscFunctionReturn(PETSC_SUCCESS); 5352 } 5353 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5354 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5355 else PetscCall(DMGetDimension(dm, &depth)); 5356 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5357 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5358 PetscFunctionReturn(PETSC_SUCCESS); 5359 } 5360 5361 /*@ 5362 DMPlexGetPointDepth - Get the `depth` of a given point 5363 5364 Not Collective 5365 5366 Input Parameters: 5367 + dm - The `DMPLEX` object 5368 - point - The point 5369 5370 Output Parameter: 5371 . depth - The depth of the `point` 5372 5373 Level: intermediate 5374 5375 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5376 @*/ 5377 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5378 { 5379 PetscFunctionBegin; 5380 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5381 PetscAssertPointer(depth, 3); 5382 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5383 PetscFunctionReturn(PETSC_SUCCESS); 5384 } 5385 5386 /*@ 5387 DMPlexGetPointHeight - Get the `height` of a given point 5388 5389 Not Collective 5390 5391 Input Parameters: 5392 + dm - The `DMPLEX` object 5393 - point - The point 5394 5395 Output Parameter: 5396 . height - The height of the `point` 5397 5398 Level: intermediate 5399 5400 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5401 @*/ 5402 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5403 { 5404 PetscInt n, pDepth; 5405 5406 PetscFunctionBegin; 5407 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5408 PetscAssertPointer(height, 3); 5409 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5410 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5411 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5412 PetscFunctionReturn(PETSC_SUCCESS); 5413 } 5414 5415 /*@ 5416 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5417 5418 Not Collective 5419 5420 Input Parameter: 5421 . dm - The `DMPLEX` object 5422 5423 Output Parameter: 5424 . celltypeLabel - The `DMLabel` recording cell polytope type 5425 5426 Level: developer 5427 5428 Note: 5429 This function will trigger automatica computation of cell types. This can be disabled by calling 5430 `DMCreateLabel`(dm, "celltype") beforehand. 5431 5432 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5433 @*/ 5434 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5435 { 5436 PetscFunctionBegin; 5437 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5438 PetscAssertPointer(celltypeLabel, 2); 5439 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5440 *celltypeLabel = dm->celltypeLabel; 5441 PetscFunctionReturn(PETSC_SUCCESS); 5442 } 5443 5444 /*@ 5445 DMPlexGetCellType - Get the polytope type of a given cell 5446 5447 Not Collective 5448 5449 Input Parameters: 5450 + dm - The `DMPLEX` object 5451 - cell - The cell 5452 5453 Output Parameter: 5454 . celltype - The polytope type of the cell 5455 5456 Level: intermediate 5457 5458 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5459 @*/ 5460 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5461 { 5462 DM_Plex *mesh = (DM_Plex *)dm->data; 5463 DMLabel label; 5464 PetscInt ct; 5465 5466 PetscFunctionBegin; 5467 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5468 PetscAssertPointer(celltype, 3); 5469 if (mesh->tr) { 5470 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5471 } else { 5472 PetscInt pStart, pEnd; 5473 5474 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5475 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5476 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5477 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5478 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5479 for (PetscInt p = pStart; p < pEnd; p++) { 5480 PetscCall(DMLabelGetValue(label, p, &ct)); 5481 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5482 } 5483 } 5484 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5485 if (PetscDefined(USE_DEBUG)) { 5486 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5487 PetscCall(DMLabelGetValue(label, cell, &ct)); 5488 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5489 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5490 } 5491 } 5492 PetscFunctionReturn(PETSC_SUCCESS); 5493 } 5494 5495 /*@ 5496 DMPlexSetCellType - Set the polytope type of a given cell 5497 5498 Not Collective 5499 5500 Input Parameters: 5501 + dm - The `DMPLEX` object 5502 . cell - The cell 5503 - celltype - The polytope type of the cell 5504 5505 Level: advanced 5506 5507 Note: 5508 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5509 is executed. This function will override the computed type. However, if automatic classification will not succeed 5510 and a user wants to manually specify all types, the classification must be disabled by calling 5511 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5512 5513 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5514 @*/ 5515 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5516 { 5517 DM_Plex *mesh = (DM_Plex *)dm->data; 5518 DMLabel label; 5519 PetscInt pStart, pEnd; 5520 5521 PetscFunctionBegin; 5522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5523 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5524 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5525 PetscCall(DMLabelSetValue(label, cell, celltype)); 5526 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5527 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5528 PetscFunctionReturn(PETSC_SUCCESS); 5529 } 5530 5531 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5532 { 5533 PetscSection section; 5534 PetscInt maxHeight; 5535 const char *prefix; 5536 5537 PetscFunctionBegin; 5538 PetscCall(DMClone(dm, cdm)); 5539 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5540 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5541 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5542 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5543 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5544 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5545 PetscCall(DMSetLocalSection(*cdm, section)); 5546 PetscCall(PetscSectionDestroy(§ion)); 5547 5548 PetscCall(DMSetNumFields(*cdm, 1)); 5549 PetscCall(DMCreateDS(*cdm)); 5550 (*cdm)->cloneOpts = PETSC_TRUE; 5551 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5552 PetscFunctionReturn(PETSC_SUCCESS); 5553 } 5554 5555 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5556 { 5557 Vec coordsLocal, cellCoordsLocal; 5558 DM coordsDM, cellCoordsDM; 5559 5560 PetscFunctionBegin; 5561 *field = NULL; 5562 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5563 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5564 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5565 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5566 if (coordsLocal && coordsDM) { 5567 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5568 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5569 } 5570 PetscFunctionReturn(PETSC_SUCCESS); 5571 } 5572 5573 /*@C 5574 DMPlexGetConeSection - Return a section which describes the layout of cone data 5575 5576 Not Collective 5577 5578 Input Parameter: 5579 . dm - The `DMPLEX` object 5580 5581 Output Parameter: 5582 . section - The `PetscSection` object 5583 5584 Level: developer 5585 5586 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5587 @*/ 5588 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5589 { 5590 DM_Plex *mesh = (DM_Plex *)dm->data; 5591 5592 PetscFunctionBegin; 5593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5594 if (section) *section = mesh->coneSection; 5595 PetscFunctionReturn(PETSC_SUCCESS); 5596 } 5597 5598 /*@C 5599 DMPlexGetSupportSection - Return a section which describes the layout of support data 5600 5601 Not Collective 5602 5603 Input Parameter: 5604 . dm - The `DMPLEX` object 5605 5606 Output Parameter: 5607 . section - The `PetscSection` object 5608 5609 Level: developer 5610 5611 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5612 @*/ 5613 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5614 { 5615 DM_Plex *mesh = (DM_Plex *)dm->data; 5616 5617 PetscFunctionBegin; 5618 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5619 if (section) *section = mesh->supportSection; 5620 PetscFunctionReturn(PETSC_SUCCESS); 5621 } 5622 5623 /*@C 5624 DMPlexGetCones - Return cone data 5625 5626 Not Collective 5627 5628 Input Parameter: 5629 . dm - The `DMPLEX` object 5630 5631 Output Parameter: 5632 . cones - The cone for each point 5633 5634 Level: developer 5635 5636 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5637 @*/ 5638 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5639 { 5640 DM_Plex *mesh = (DM_Plex *)dm->data; 5641 5642 PetscFunctionBegin; 5643 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5644 if (cones) *cones = mesh->cones; 5645 PetscFunctionReturn(PETSC_SUCCESS); 5646 } 5647 5648 /*@C 5649 DMPlexGetConeOrientations - Return cone orientation data 5650 5651 Not Collective 5652 5653 Input Parameter: 5654 . dm - The `DMPLEX` object 5655 5656 Output Parameter: 5657 . coneOrientations - The array of cone orientations for all points 5658 5659 Level: developer 5660 5661 Notes: 5662 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5663 5664 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5665 5666 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5667 @*/ 5668 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5669 { 5670 DM_Plex *mesh = (DM_Plex *)dm->data; 5671 5672 PetscFunctionBegin; 5673 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5674 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5675 PetscFunctionReturn(PETSC_SUCCESS); 5676 } 5677 5678 /******************************** FEM Support **********************************/ 5679 5680 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5681 { 5682 PetscInt depth; 5683 5684 PetscFunctionBegin; 5685 PetscCall(DMPlexGetDepth(plex, &depth)); 5686 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5687 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5688 PetscFunctionReturn(PETSC_SUCCESS); 5689 } 5690 5691 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5692 { 5693 PetscInt depth; 5694 5695 PetscFunctionBegin; 5696 PetscCall(DMPlexGetDepth(plex, &depth)); 5697 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5698 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5699 PetscFunctionReturn(PETSC_SUCCESS); 5700 } 5701 5702 /* 5703 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5704 representing a line in the section. 5705 */ 5706 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5707 { 5708 PetscObject obj; 5709 PetscClassId id; 5710 PetscFE fe = NULL; 5711 5712 PetscFunctionBeginHot; 5713 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5714 PetscCall(DMGetField(dm, field, NULL, &obj)); 5715 PetscCall(PetscObjectGetClassId(obj, &id)); 5716 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5717 5718 if (!fe) { 5719 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5720 /* An order k SEM disc has k-1 dofs on an edge */ 5721 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5722 *k = *k / *Nc + 1; 5723 } else { 5724 PetscInt dual_space_size, dim; 5725 PetscDualSpace dsp; 5726 5727 PetscCall(DMGetDimension(dm, &dim)); 5728 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5729 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5730 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5731 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5732 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5733 } 5734 PetscFunctionReturn(PETSC_SUCCESS); 5735 } 5736 5737 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5738 { 5739 PetscFunctionBeginHot; 5740 if (tensor) { 5741 *dof = PetscPowInt(k + 1, dim); 5742 } else { 5743 switch (dim) { 5744 case 1: 5745 *dof = k + 1; 5746 break; 5747 case 2: 5748 *dof = ((k + 1) * (k + 2)) / 2; 5749 break; 5750 case 3: 5751 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5752 break; 5753 default: 5754 *dof = 0; 5755 } 5756 } 5757 PetscFunctionReturn(PETSC_SUCCESS); 5758 } 5759 5760 /*@ 5761 5762 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5763 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5764 section provided (or the section of the `DM`). 5765 5766 Input Parameters: 5767 + dm - The `DM` 5768 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5769 - section - The `PetscSection` to reorder, or `NULL` for the default section 5770 5771 Example: 5772 A typical interpolated single-quad mesh might order points as 5773 .vb 5774 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5775 5776 v4 -- e6 -- v3 5777 | | 5778 e7 c0 e8 5779 | | 5780 v1 -- e5 -- v2 5781 .ve 5782 5783 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5784 dofs in the order of points, e.g., 5785 .vb 5786 c0 -> [0,1,2,3] 5787 v1 -> [4] 5788 ... 5789 e5 -> [8, 9] 5790 .ve 5791 5792 which corresponds to the dofs 5793 .vb 5794 6 10 11 7 5795 13 2 3 15 5796 12 0 1 14 5797 4 8 9 5 5798 .ve 5799 5800 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5801 .vb 5802 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5803 .ve 5804 5805 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5806 .vb 5807 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5808 .ve 5809 5810 Level: developer 5811 5812 Notes: 5813 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5814 degree of the basis. 5815 5816 This is required to run with libCEED. 5817 5818 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5819 @*/ 5820 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5821 { 5822 DMLabel label; 5823 PetscInt dim, depth = -1, eStart = -1, Nf; 5824 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5825 5826 PetscFunctionBegin; 5827 PetscCall(DMGetDimension(dm, &dim)); 5828 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5829 if (point < 0) { 5830 PetscInt sStart, sEnd; 5831 5832 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5833 point = sEnd - sStart ? sStart : point; 5834 } 5835 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5836 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5837 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5838 if (depth == 1) { 5839 eStart = point; 5840 } else if (depth == dim) { 5841 const PetscInt *cone; 5842 5843 PetscCall(DMPlexGetCone(dm, point, &cone)); 5844 if (dim == 2) eStart = cone[0]; 5845 else if (dim == 3) { 5846 const PetscInt *cone2; 5847 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5848 eStart = cone2[0]; 5849 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5850 } else PetscCheck(depth < 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5851 5852 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5853 for (PetscInt d = 1; d <= dim; d++) { 5854 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5855 PetscInt *perm; 5856 5857 for (f = 0; f < Nf; ++f) { 5858 PetscInt dof; 5859 5860 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5861 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5862 if (!continuous && d < dim) continue; 5863 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5864 size += dof * Nc; 5865 } 5866 PetscCall(PetscMalloc1(size, &perm)); 5867 for (f = 0; f < Nf; ++f) { 5868 switch (d) { 5869 case 1: 5870 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5871 if (!continuous && d < dim) continue; 5872 /* 5873 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5874 We want [ vtx0; edge of length k-1; vtx1 ] 5875 */ 5876 if (continuous) { 5877 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5878 for (i = 0; i < k - 1; i++) 5879 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5880 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5881 foffset = offset; 5882 } else { 5883 PetscInt dof; 5884 5885 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5886 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5887 foffset = offset; 5888 } 5889 break; 5890 case 2: 5891 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5892 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5893 if (!continuous && d < dim) continue; 5894 /* The SEM order is 5895 5896 v_lb, {e_b}, v_rb, 5897 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5898 v_lt, reverse {e_t}, v_rt 5899 */ 5900 if (continuous) { 5901 const PetscInt of = 0; 5902 const PetscInt oeb = of + PetscSqr(k - 1); 5903 const PetscInt oer = oeb + (k - 1); 5904 const PetscInt oet = oer + (k - 1); 5905 const PetscInt oel = oet + (k - 1); 5906 const PetscInt ovlb = oel + (k - 1); 5907 const PetscInt ovrb = ovlb + 1; 5908 const PetscInt ovrt = ovrb + 1; 5909 const PetscInt ovlt = ovrt + 1; 5910 PetscInt o; 5911 5912 /* bottom */ 5913 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5914 for (o = oeb; o < oer; ++o) 5915 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5916 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5917 /* middle */ 5918 for (i = 0; i < k - 1; ++i) { 5919 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5920 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5921 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5922 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5923 } 5924 /* top */ 5925 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5926 for (o = oel - 1; o >= oet; --o) 5927 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5928 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5929 foffset = offset; 5930 } else { 5931 PetscInt dof; 5932 5933 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5934 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5935 foffset = offset; 5936 } 5937 break; 5938 case 3: 5939 /* The original hex closure is 5940 5941 {c, 5942 f_b, f_t, f_f, f_b, f_r, f_l, 5943 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5944 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5945 */ 5946 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5947 if (!continuous && d < dim) continue; 5948 /* The SEM order is 5949 Bottom Slice 5950 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5951 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5952 v_blb, {e_bb}, v_brb, 5953 5954 Middle Slice (j) 5955 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5956 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5957 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5958 5959 Top Slice 5960 v_tlf, {e_tf}, v_trf, 5961 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5962 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5963 */ 5964 if (continuous) { 5965 const PetscInt oc = 0; 5966 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5967 const PetscInt oft = ofb + PetscSqr(k - 1); 5968 const PetscInt off = oft + PetscSqr(k - 1); 5969 const PetscInt ofk = off + PetscSqr(k - 1); 5970 const PetscInt ofr = ofk + PetscSqr(k - 1); 5971 const PetscInt ofl = ofr + PetscSqr(k - 1); 5972 const PetscInt oebl = ofl + PetscSqr(k - 1); 5973 const PetscInt oebb = oebl + (k - 1); 5974 const PetscInt oebr = oebb + (k - 1); 5975 const PetscInt oebf = oebr + (k - 1); 5976 const PetscInt oetf = oebf + (k - 1); 5977 const PetscInt oetr = oetf + (k - 1); 5978 const PetscInt oetb = oetr + (k - 1); 5979 const PetscInt oetl = oetb + (k - 1); 5980 const PetscInt oerf = oetl + (k - 1); 5981 const PetscInt oelf = oerf + (k - 1); 5982 const PetscInt oelb = oelf + (k - 1); 5983 const PetscInt oerb = oelb + (k - 1); 5984 const PetscInt ovblf = oerb + (k - 1); 5985 const PetscInt ovblb = ovblf + 1; 5986 const PetscInt ovbrb = ovblb + 1; 5987 const PetscInt ovbrf = ovbrb + 1; 5988 const PetscInt ovtlf = ovbrf + 1; 5989 const PetscInt ovtrf = ovtlf + 1; 5990 const PetscInt ovtrb = ovtrf + 1; 5991 const PetscInt ovtlb = ovtrb + 1; 5992 PetscInt o, n; 5993 5994 /* Bottom Slice */ 5995 /* bottom */ 5996 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5997 for (o = oetf - 1; o >= oebf; --o) 5998 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5999 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6000 /* middle */ 6001 for (i = 0; i < k - 1; ++i) { 6002 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6003 for (n = 0; n < k - 1; ++n) { 6004 o = ofb + n * (k - 1) + i; 6005 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6006 } 6007 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6008 } 6009 /* top */ 6010 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6011 for (o = oebb; o < oebr; ++o) 6012 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6013 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6014 6015 /* Middle Slice */ 6016 for (j = 0; j < k - 1; ++j) { 6017 /* bottom */ 6018 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6019 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6020 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6021 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6022 /* middle */ 6023 for (i = 0; i < k - 1; ++i) { 6024 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6025 for (n = 0; n < k - 1; ++n) 6026 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6027 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6028 } 6029 /* top */ 6030 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6031 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6032 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6033 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6034 } 6035 6036 /* Top Slice */ 6037 /* bottom */ 6038 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6039 for (o = oetf; o < oetr; ++o) 6040 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6041 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6042 /* middle */ 6043 for (i = 0; i < k - 1; ++i) { 6044 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6045 for (n = 0; n < k - 1; ++n) 6046 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6047 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6048 } 6049 /* top */ 6050 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6051 for (o = oetl - 1; o >= oetb; --o) 6052 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6053 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6054 6055 foffset = offset; 6056 } else { 6057 PetscInt dof; 6058 6059 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6060 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6061 foffset = offset; 6062 } 6063 break; 6064 default: 6065 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6066 } 6067 } 6068 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6069 /* Check permutation */ 6070 { 6071 PetscInt *check; 6072 6073 PetscCall(PetscMalloc1(size, &check)); 6074 for (i = 0; i < size; ++i) { 6075 check[i] = -1; 6076 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6077 } 6078 for (i = 0; i < size; ++i) check[perm[i]] = i; 6079 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6080 PetscCall(PetscFree(check)); 6081 } 6082 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6083 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6084 PetscInt *loc_perm; 6085 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6086 for (PetscInt i = 0; i < size; i++) { 6087 loc_perm[i] = perm[i]; 6088 loc_perm[size + i] = size + perm[i]; 6089 } 6090 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6091 } 6092 } 6093 PetscFunctionReturn(PETSC_SUCCESS); 6094 } 6095 6096 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6097 { 6098 PetscDS prob; 6099 PetscInt depth, Nf, h; 6100 DMLabel label; 6101 6102 PetscFunctionBeginHot; 6103 PetscCall(DMGetDS(dm, &prob)); 6104 Nf = prob->Nf; 6105 label = dm->depthLabel; 6106 *dspace = NULL; 6107 if (field < Nf) { 6108 PetscObject disc = prob->disc[field]; 6109 6110 if (disc->classid == PETSCFE_CLASSID) { 6111 PetscDualSpace dsp; 6112 6113 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6114 PetscCall(DMLabelGetNumValues(label, &depth)); 6115 PetscCall(DMLabelGetValue(label, point, &h)); 6116 h = depth - 1 - h; 6117 if (h) { 6118 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6119 } else { 6120 *dspace = dsp; 6121 } 6122 } 6123 } 6124 PetscFunctionReturn(PETSC_SUCCESS); 6125 } 6126 6127 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6128 { 6129 PetscScalar *array; 6130 const PetscScalar *vArray; 6131 const PetscInt *cone, *coneO; 6132 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6133 6134 PetscFunctionBeginHot; 6135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6136 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6137 PetscCall(DMPlexGetCone(dm, point, &cone)); 6138 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6139 if (!values || !*values) { 6140 if ((point >= pStart) && (point < pEnd)) { 6141 PetscInt dof; 6142 6143 PetscCall(PetscSectionGetDof(section, point, &dof)); 6144 size += dof; 6145 } 6146 for (p = 0; p < numPoints; ++p) { 6147 const PetscInt cp = cone[p]; 6148 PetscInt dof; 6149 6150 if ((cp < pStart) || (cp >= pEnd)) continue; 6151 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6152 size += dof; 6153 } 6154 if (!values) { 6155 if (csize) *csize = size; 6156 PetscFunctionReturn(PETSC_SUCCESS); 6157 } 6158 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6159 } else { 6160 array = *values; 6161 } 6162 size = 0; 6163 PetscCall(VecGetArrayRead(v, &vArray)); 6164 if ((point >= pStart) && (point < pEnd)) { 6165 PetscInt dof, off, d; 6166 const PetscScalar *varr; 6167 6168 PetscCall(PetscSectionGetDof(section, point, &dof)); 6169 PetscCall(PetscSectionGetOffset(section, point, &off)); 6170 varr = PetscSafePointerPlusOffset(vArray, off); 6171 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6172 size += dof; 6173 } 6174 for (p = 0; p < numPoints; ++p) { 6175 const PetscInt cp = cone[p]; 6176 PetscInt o = coneO[p]; 6177 PetscInt dof, off, d; 6178 const PetscScalar *varr; 6179 6180 if ((cp < pStart) || (cp >= pEnd)) continue; 6181 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6182 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6183 varr = PetscSafePointerPlusOffset(vArray, off); 6184 if (o >= 0) { 6185 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6186 } else { 6187 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6188 } 6189 size += dof; 6190 } 6191 PetscCall(VecRestoreArrayRead(v, &vArray)); 6192 if (!*values) { 6193 if (csize) *csize = size; 6194 *values = array; 6195 } else { 6196 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6197 *csize = size; 6198 } 6199 PetscFunctionReturn(PETSC_SUCCESS); 6200 } 6201 6202 /* Compress out points not in the section */ 6203 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6204 { 6205 const PetscInt np = *numPoints; 6206 PetscInt pStart, pEnd, p, q; 6207 6208 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6209 for (p = 0, q = 0; p < np; ++p) { 6210 const PetscInt r = points[p * 2]; 6211 if ((r >= pStart) && (r < pEnd)) { 6212 points[q * 2] = r; 6213 points[q * 2 + 1] = points[p * 2 + 1]; 6214 ++q; 6215 } 6216 } 6217 *numPoints = q; 6218 return PETSC_SUCCESS; 6219 } 6220 6221 /* Compressed closure does not apply closure permutation */ 6222 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6223 { 6224 const PetscInt *cla = NULL; 6225 PetscInt np, *pts = NULL; 6226 6227 PetscFunctionBeginHot; 6228 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6229 if (!ornt && *clPoints) { 6230 PetscInt dof, off; 6231 6232 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6233 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6234 PetscCall(ISGetIndices(*clPoints, &cla)); 6235 np = dof / 2; 6236 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6237 } else { 6238 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6239 PetscCall(CompressPoints_Private(section, &np, pts)); 6240 } 6241 *numPoints = np; 6242 *points = pts; 6243 *clp = cla; 6244 PetscFunctionReturn(PETSC_SUCCESS); 6245 } 6246 6247 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6248 { 6249 PetscFunctionBeginHot; 6250 if (!*clPoints) { 6251 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6252 } else { 6253 PetscCall(ISRestoreIndices(*clPoints, clp)); 6254 } 6255 *numPoints = 0; 6256 *points = NULL; 6257 *clSec = NULL; 6258 *clPoints = NULL; 6259 *clp = NULL; 6260 PetscFunctionReturn(PETSC_SUCCESS); 6261 } 6262 6263 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6264 { 6265 PetscInt offset = 0, p; 6266 const PetscInt **perms = NULL; 6267 const PetscScalar **flips = NULL; 6268 6269 PetscFunctionBeginHot; 6270 *size = 0; 6271 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6272 for (p = 0; p < numPoints; p++) { 6273 const PetscInt point = points[2 * p]; 6274 const PetscInt *perm = perms ? perms[p] : NULL; 6275 const PetscScalar *flip = flips ? flips[p] : NULL; 6276 PetscInt dof, off, d; 6277 const PetscScalar *varr; 6278 6279 PetscCall(PetscSectionGetDof(section, point, &dof)); 6280 PetscCall(PetscSectionGetOffset(section, point, &off)); 6281 varr = PetscSafePointerPlusOffset(vArray, off); 6282 if (clperm) { 6283 if (perm) { 6284 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6285 } else { 6286 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6287 } 6288 if (flip) { 6289 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6290 } 6291 } else { 6292 if (perm) { 6293 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6294 } else { 6295 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6296 } 6297 if (flip) { 6298 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6299 } 6300 } 6301 offset += dof; 6302 } 6303 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6304 *size = offset; 6305 PetscFunctionReturn(PETSC_SUCCESS); 6306 } 6307 6308 static inline PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6309 { 6310 PetscInt offset = 0, f; 6311 6312 PetscFunctionBeginHot; 6313 *size = 0; 6314 for (f = 0; f < numFields; ++f) { 6315 PetscInt p; 6316 const PetscInt **perms = NULL; 6317 const PetscScalar **flips = NULL; 6318 6319 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6320 for (p = 0; p < numPoints; p++) { 6321 const PetscInt point = points[2 * p]; 6322 PetscInt fdof, foff, b; 6323 const PetscScalar *varr; 6324 const PetscInt *perm = perms ? perms[p] : NULL; 6325 const PetscScalar *flip = flips ? flips[p] : NULL; 6326 6327 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6328 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6329 varr = &vArray[foff]; 6330 if (clperm) { 6331 if (perm) { 6332 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6333 } else { 6334 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6335 } 6336 if (flip) { 6337 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6338 } 6339 } else { 6340 if (perm) { 6341 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6342 } else { 6343 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6344 } 6345 if (flip) { 6346 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6347 } 6348 } 6349 offset += fdof; 6350 } 6351 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6352 } 6353 *size = offset; 6354 PetscFunctionReturn(PETSC_SUCCESS); 6355 } 6356 6357 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6358 { 6359 PetscSection clSection; 6360 IS clPoints; 6361 PetscInt *points = NULL; 6362 const PetscInt *clp, *perm = NULL; 6363 PetscInt depth, numFields, numPoints, asize; 6364 6365 PetscFunctionBeginHot; 6366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6367 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6368 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6369 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6370 PetscCall(DMPlexGetDepth(dm, &depth)); 6371 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6372 if (depth == 1 && numFields < 2) { 6373 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6374 PetscFunctionReturn(PETSC_SUCCESS); 6375 } 6376 /* Get points */ 6377 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6378 /* Get sizes */ 6379 asize = 0; 6380 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6381 PetscInt dof; 6382 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6383 asize += dof; 6384 } 6385 if (values) { 6386 const PetscScalar *vArray; 6387 PetscInt size; 6388 6389 if (*values) { 6390 PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize); 6391 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6392 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6393 PetscCall(VecGetArrayRead(v, &vArray)); 6394 /* Get values */ 6395 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6396 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6397 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6398 /* Cleanup array */ 6399 PetscCall(VecRestoreArrayRead(v, &vArray)); 6400 } 6401 if (csize) *csize = asize; 6402 /* Cleanup points */ 6403 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6404 PetscFunctionReturn(PETSC_SUCCESS); 6405 } 6406 6407 /*@C 6408 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6409 6410 Not collective 6411 6412 Input Parameters: 6413 + dm - The `DM` 6414 . section - The section describing the layout in `v`, or `NULL` to use the default section 6415 . v - The local vector 6416 - point - The point in the `DM` 6417 6418 Input/Output Parameters: 6419 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6420 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6421 if the user provided `NULL`, it is a borrowed array and should not be freed 6422 6423 Level: intermediate 6424 6425 Notes: 6426 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6427 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6428 assembly function, and a user may already have allocated storage for this operation. 6429 6430 A typical use could be 6431 .vb 6432 values = NULL; 6433 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6434 for (cl = 0; cl < clSize; ++cl) { 6435 <Compute on closure> 6436 } 6437 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6438 .ve 6439 or 6440 .vb 6441 PetscMalloc1(clMaxSize, &values); 6442 for (p = pStart; p < pEnd; ++p) { 6443 clSize = clMaxSize; 6444 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6445 for (cl = 0; cl < clSize; ++cl) { 6446 <Compute on closure> 6447 } 6448 } 6449 PetscFree(values); 6450 .ve 6451 6452 Fortran Notes: 6453 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6454 6455 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6456 @*/ 6457 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6458 { 6459 PetscFunctionBeginHot; 6460 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6461 PetscFunctionReturn(PETSC_SUCCESS); 6462 } 6463 6464 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6465 { 6466 DMLabel depthLabel; 6467 PetscSection clSection; 6468 IS clPoints; 6469 PetscScalar *array; 6470 const PetscScalar *vArray; 6471 PetscInt *points = NULL; 6472 const PetscInt *clp, *perm = NULL; 6473 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6474 6475 PetscFunctionBeginHot; 6476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6477 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6478 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6479 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6480 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6481 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6482 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6483 if (mdepth == 1 && numFields < 2) { 6484 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6485 PetscFunctionReturn(PETSC_SUCCESS); 6486 } 6487 /* Get points */ 6488 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6489 for (clsize = 0, p = 0; p < Np; p++) { 6490 PetscInt dof; 6491 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6492 clsize += dof; 6493 } 6494 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6495 /* Filter points */ 6496 for (p = 0; p < numPoints * 2; p += 2) { 6497 PetscInt dep; 6498 6499 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6500 if (dep != depth) continue; 6501 points[Np * 2 + 0] = points[p]; 6502 points[Np * 2 + 1] = points[p + 1]; 6503 ++Np; 6504 } 6505 /* Get array */ 6506 if (!values || !*values) { 6507 PetscInt asize = 0, dof; 6508 6509 for (p = 0; p < Np * 2; p += 2) { 6510 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6511 asize += dof; 6512 } 6513 if (!values) { 6514 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6515 if (csize) *csize = asize; 6516 PetscFunctionReturn(PETSC_SUCCESS); 6517 } 6518 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6519 } else { 6520 array = *values; 6521 } 6522 PetscCall(VecGetArrayRead(v, &vArray)); 6523 /* Get values */ 6524 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6525 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6526 /* Cleanup points */ 6527 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6528 /* Cleanup array */ 6529 PetscCall(VecRestoreArrayRead(v, &vArray)); 6530 if (!*values) { 6531 if (csize) *csize = size; 6532 *values = array; 6533 } else { 6534 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6535 *csize = size; 6536 } 6537 PetscFunctionReturn(PETSC_SUCCESS); 6538 } 6539 6540 /*@C 6541 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6542 6543 Not collective 6544 6545 Input Parameters: 6546 + dm - The `DM` 6547 . section - The section describing the layout in `v`, or `NULL` to use the default section 6548 . v - The local vector 6549 . point - The point in the `DM` 6550 . csize - The number of values in the closure, or `NULL` 6551 - values - The array of values, which is a borrowed array and should not be freed 6552 6553 Level: intermediate 6554 6555 Note: 6556 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6557 6558 Fortran Notes: 6559 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6560 6561 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6562 @*/ 6563 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6564 { 6565 PetscInt size = 0; 6566 6567 PetscFunctionBegin; 6568 /* Should work without recalculating size */ 6569 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6570 *values = NULL; 6571 PetscFunctionReturn(PETSC_SUCCESS); 6572 } 6573 6574 static inline void add(PetscScalar *x, PetscScalar y) 6575 { 6576 *x += y; 6577 } 6578 static inline void insert(PetscScalar *x, PetscScalar y) 6579 { 6580 *x = y; 6581 } 6582 6583 static inline PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) 6584 { 6585 PetscInt cdof; /* The number of constraints on this point */ 6586 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6587 PetscScalar *a; 6588 PetscInt off, cind = 0, k; 6589 6590 PetscFunctionBegin; 6591 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6592 PetscCall(PetscSectionGetOffset(section, point, &off)); 6593 a = &array[off]; 6594 if (!cdof || setBC) { 6595 if (clperm) { 6596 if (perm) { 6597 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6598 } else { 6599 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6600 } 6601 } else { 6602 if (perm) { 6603 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6604 } else { 6605 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6606 } 6607 } 6608 } else { 6609 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6610 if (clperm) { 6611 if (perm) { 6612 for (k = 0; k < dof; ++k) { 6613 if ((cind < cdof) && (k == cdofs[cind])) { 6614 ++cind; 6615 continue; 6616 } 6617 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6618 } 6619 } else { 6620 for (k = 0; k < dof; ++k) { 6621 if ((cind < cdof) && (k == cdofs[cind])) { 6622 ++cind; 6623 continue; 6624 } 6625 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6626 } 6627 } 6628 } else { 6629 if (perm) { 6630 for (k = 0; k < dof; ++k) { 6631 if ((cind < cdof) && (k == cdofs[cind])) { 6632 ++cind; 6633 continue; 6634 } 6635 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6636 } 6637 } else { 6638 for (k = 0; k < dof; ++k) { 6639 if ((cind < cdof) && (k == cdofs[cind])) { 6640 ++cind; 6641 continue; 6642 } 6643 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6644 } 6645 } 6646 } 6647 } 6648 PetscFunctionReturn(PETSC_SUCCESS); 6649 } 6650 6651 static inline PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) 6652 { 6653 PetscInt cdof; /* The number of constraints on this point */ 6654 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6655 PetscScalar *a; 6656 PetscInt off, cind = 0, k; 6657 6658 PetscFunctionBegin; 6659 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6660 PetscCall(PetscSectionGetOffset(section, point, &off)); 6661 a = &array[off]; 6662 if (cdof) { 6663 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6664 if (clperm) { 6665 if (perm) { 6666 for (k = 0; k < dof; ++k) { 6667 if ((cind < cdof) && (k == cdofs[cind])) { 6668 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6669 cind++; 6670 } 6671 } 6672 } else { 6673 for (k = 0; k < dof; ++k) { 6674 if ((cind < cdof) && (k == cdofs[cind])) { 6675 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6676 cind++; 6677 } 6678 } 6679 } 6680 } else { 6681 if (perm) { 6682 for (k = 0; k < dof; ++k) { 6683 if ((cind < cdof) && (k == cdofs[cind])) { 6684 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6685 cind++; 6686 } 6687 } 6688 } else { 6689 for (k = 0; k < dof; ++k) { 6690 if ((cind < cdof) && (k == cdofs[cind])) { 6691 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6692 cind++; 6693 } 6694 } 6695 } 6696 } 6697 } 6698 PetscFunctionReturn(PETSC_SUCCESS); 6699 } 6700 6701 static inline PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, const PetscInt *perm, const PetscScalar *flip, PetscInt f, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 6702 { 6703 PetscScalar *a; 6704 PetscInt fdof, foff, fcdof, foffset = *offset; 6705 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6706 PetscInt cind = 0, b; 6707 6708 PetscFunctionBegin; 6709 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6710 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6711 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6712 a = &array[foff]; 6713 if (!fcdof || setBC) { 6714 if (clperm) { 6715 if (perm) { 6716 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6717 } else { 6718 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6719 } 6720 } else { 6721 if (perm) { 6722 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6723 } else { 6724 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6725 } 6726 } 6727 } else { 6728 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6729 if (clperm) { 6730 if (perm) { 6731 for (b = 0; b < fdof; b++) { 6732 if ((cind < fcdof) && (b == fcdofs[cind])) { 6733 ++cind; 6734 continue; 6735 } 6736 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6737 } 6738 } else { 6739 for (b = 0; b < fdof; b++) { 6740 if ((cind < fcdof) && (b == fcdofs[cind])) { 6741 ++cind; 6742 continue; 6743 } 6744 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6745 } 6746 } 6747 } else { 6748 if (perm) { 6749 for (b = 0; b < fdof; b++) { 6750 if ((cind < fcdof) && (b == fcdofs[cind])) { 6751 ++cind; 6752 continue; 6753 } 6754 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6755 } 6756 } else { 6757 for (b = 0; b < fdof; b++) { 6758 if ((cind < fcdof) && (b == fcdofs[cind])) { 6759 ++cind; 6760 continue; 6761 } 6762 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6763 } 6764 } 6765 } 6766 } 6767 *offset += fdof; 6768 PetscFunctionReturn(PETSC_SUCCESS); 6769 } 6770 6771 static inline PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar *, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 6772 { 6773 PetscScalar *a; 6774 PetscInt fdof, foff, fcdof, foffset = *offset; 6775 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6776 PetscInt Nc, cind = 0, ncind = 0, b; 6777 PetscBool ncSet, fcSet; 6778 6779 PetscFunctionBegin; 6780 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6781 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6782 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6783 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6784 a = &array[foff]; 6785 if (fcdof) { 6786 /* We just override fcdof and fcdofs with Ncc and comps */ 6787 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6788 if (clperm) { 6789 if (perm) { 6790 if (comps) { 6791 for (b = 0; b < fdof; b++) { 6792 ncSet = fcSet = PETSC_FALSE; 6793 if (b % Nc == comps[ncind]) { 6794 ncind = (ncind + 1) % Ncc; 6795 ncSet = PETSC_TRUE; 6796 } 6797 if ((cind < fcdof) && (b == fcdofs[cind])) { 6798 ++cind; 6799 fcSet = PETSC_TRUE; 6800 } 6801 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6802 } 6803 } else { 6804 for (b = 0; b < fdof; b++) { 6805 if ((cind < fcdof) && (b == fcdofs[cind])) { 6806 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6807 ++cind; 6808 } 6809 } 6810 } 6811 } else { 6812 if (comps) { 6813 for (b = 0; b < fdof; b++) { 6814 ncSet = fcSet = PETSC_FALSE; 6815 if (b % Nc == comps[ncind]) { 6816 ncind = (ncind + 1) % Ncc; 6817 ncSet = PETSC_TRUE; 6818 } 6819 if ((cind < fcdof) && (b == fcdofs[cind])) { 6820 ++cind; 6821 fcSet = PETSC_TRUE; 6822 } 6823 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6824 } 6825 } else { 6826 for (b = 0; b < fdof; b++) { 6827 if ((cind < fcdof) && (b == fcdofs[cind])) { 6828 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6829 ++cind; 6830 } 6831 } 6832 } 6833 } 6834 } else { 6835 if (perm) { 6836 if (comps) { 6837 for (b = 0; b < fdof; b++) { 6838 ncSet = fcSet = PETSC_FALSE; 6839 if (b % Nc == comps[ncind]) { 6840 ncind = (ncind + 1) % Ncc; 6841 ncSet = PETSC_TRUE; 6842 } 6843 if ((cind < fcdof) && (b == fcdofs[cind])) { 6844 ++cind; 6845 fcSet = PETSC_TRUE; 6846 } 6847 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6848 } 6849 } else { 6850 for (b = 0; b < fdof; b++) { 6851 if ((cind < fcdof) && (b == fcdofs[cind])) { 6852 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6853 ++cind; 6854 } 6855 } 6856 } 6857 } else { 6858 if (comps) { 6859 for (b = 0; b < fdof; b++) { 6860 ncSet = fcSet = PETSC_FALSE; 6861 if (b % Nc == comps[ncind]) { 6862 ncind = (ncind + 1) % Ncc; 6863 ncSet = PETSC_TRUE; 6864 } 6865 if ((cind < fcdof) && (b == fcdofs[cind])) { 6866 ++cind; 6867 fcSet = PETSC_TRUE; 6868 } 6869 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6870 } 6871 } else { 6872 for (b = 0; b < fdof; b++) { 6873 if ((cind < fcdof) && (b == fcdofs[cind])) { 6874 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6875 ++cind; 6876 } 6877 } 6878 } 6879 } 6880 } 6881 } 6882 *offset += fdof; 6883 PetscFunctionReturn(PETSC_SUCCESS); 6884 } 6885 6886 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6887 { 6888 PetscScalar *array; 6889 const PetscInt *cone, *coneO; 6890 PetscInt pStart, pEnd, p, numPoints, off, dof; 6891 6892 PetscFunctionBeginHot; 6893 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6894 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6895 PetscCall(DMPlexGetCone(dm, point, &cone)); 6896 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6897 PetscCall(VecGetArray(v, &array)); 6898 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6899 const PetscInt cp = !p ? point : cone[p - 1]; 6900 const PetscInt o = !p ? 0 : coneO[p - 1]; 6901 6902 if ((cp < pStart) || (cp >= pEnd)) { 6903 dof = 0; 6904 continue; 6905 } 6906 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6907 /* ADD_VALUES */ 6908 { 6909 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6910 PetscScalar *a; 6911 PetscInt cdof, coff, cind = 0, k; 6912 6913 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6914 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6915 a = &array[coff]; 6916 if (!cdof) { 6917 if (o >= 0) { 6918 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6919 } else { 6920 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6921 } 6922 } else { 6923 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6924 if (o >= 0) { 6925 for (k = 0; k < dof; ++k) { 6926 if ((cind < cdof) && (k == cdofs[cind])) { 6927 ++cind; 6928 continue; 6929 } 6930 a[k] += values[off + k]; 6931 } 6932 } else { 6933 for (k = 0; k < dof; ++k) { 6934 if ((cind < cdof) && (k == cdofs[cind])) { 6935 ++cind; 6936 continue; 6937 } 6938 a[k] += values[off + dof - k - 1]; 6939 } 6940 } 6941 } 6942 } 6943 } 6944 PetscCall(VecRestoreArray(v, &array)); 6945 PetscFunctionReturn(PETSC_SUCCESS); 6946 } 6947 6948 /*@C 6949 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6950 6951 Not collective 6952 6953 Input Parameters: 6954 + dm - The `DM` 6955 . section - The section describing the layout in `v`, or `NULL` to use the default section 6956 . v - The local vector 6957 . point - The point in the `DM` 6958 . values - The array of values 6959 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6960 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6961 6962 Level: intermediate 6963 6964 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6965 @*/ 6966 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6967 { 6968 PetscSection clSection; 6969 IS clPoints; 6970 PetscScalar *array; 6971 PetscInt *points = NULL; 6972 const PetscInt *clp, *clperm = NULL; 6973 PetscInt depth, numFields, numPoints, p, clsize; 6974 6975 PetscFunctionBeginHot; 6976 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6977 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6978 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6979 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6980 PetscCall(DMPlexGetDepth(dm, &depth)); 6981 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6982 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6983 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6984 PetscFunctionReturn(PETSC_SUCCESS); 6985 } 6986 /* Get points */ 6987 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6988 for (clsize = 0, p = 0; p < numPoints; p++) { 6989 PetscInt dof; 6990 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6991 clsize += dof; 6992 } 6993 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6994 /* Get array */ 6995 PetscCall(VecGetArray(v, &array)); 6996 /* Get values */ 6997 if (numFields > 0) { 6998 PetscInt offset = 0, f; 6999 for (f = 0; f < numFields; ++f) { 7000 const PetscInt **perms = NULL; 7001 const PetscScalar **flips = NULL; 7002 7003 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7004 switch (mode) { 7005 case INSERT_VALUES: 7006 for (p = 0; p < numPoints; p++) { 7007 const PetscInt point = points[2 * p]; 7008 const PetscInt *perm = perms ? perms[p] : NULL; 7009 const PetscScalar *flip = flips ? flips[p] : NULL; 7010 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7011 } 7012 break; 7013 case INSERT_ALL_VALUES: 7014 for (p = 0; p < numPoints; p++) { 7015 const PetscInt point = points[2 * p]; 7016 const PetscInt *perm = perms ? perms[p] : NULL; 7017 const PetscScalar *flip = flips ? flips[p] : NULL; 7018 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7019 } 7020 break; 7021 case INSERT_BC_VALUES: 7022 for (p = 0; p < numPoints; p++) { 7023 const PetscInt point = points[2 * p]; 7024 const PetscInt *perm = perms ? perms[p] : NULL; 7025 const PetscScalar *flip = flips ? flips[p] : NULL; 7026 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7027 } 7028 break; 7029 case ADD_VALUES: 7030 for (p = 0; p < numPoints; p++) { 7031 const PetscInt point = points[2 * p]; 7032 const PetscInt *perm = perms ? perms[p] : NULL; 7033 const PetscScalar *flip = flips ? flips[p] : NULL; 7034 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7035 } 7036 break; 7037 case ADD_ALL_VALUES: 7038 for (p = 0; p < numPoints; p++) { 7039 const PetscInt point = points[2 * p]; 7040 const PetscInt *perm = perms ? perms[p] : NULL; 7041 const PetscScalar *flip = flips ? flips[p] : NULL; 7042 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7043 } 7044 break; 7045 case ADD_BC_VALUES: 7046 for (p = 0; p < numPoints; p++) { 7047 const PetscInt point = points[2 * p]; 7048 const PetscInt *perm = perms ? perms[p] : NULL; 7049 const PetscScalar *flip = flips ? flips[p] : NULL; 7050 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7051 } 7052 break; 7053 default: 7054 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7055 } 7056 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7057 } 7058 } else { 7059 PetscInt dof, off; 7060 const PetscInt **perms = NULL; 7061 const PetscScalar **flips = NULL; 7062 7063 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7064 switch (mode) { 7065 case INSERT_VALUES: 7066 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7067 const PetscInt point = points[2 * p]; 7068 const PetscInt *perm = perms ? perms[p] : NULL; 7069 const PetscScalar *flip = flips ? flips[p] : NULL; 7070 PetscCall(PetscSectionGetDof(section, point, &dof)); 7071 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7072 } 7073 break; 7074 case INSERT_ALL_VALUES: 7075 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7076 const PetscInt point = points[2 * p]; 7077 const PetscInt *perm = perms ? perms[p] : NULL; 7078 const PetscScalar *flip = flips ? flips[p] : NULL; 7079 PetscCall(PetscSectionGetDof(section, point, &dof)); 7080 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7081 } 7082 break; 7083 case INSERT_BC_VALUES: 7084 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7085 const PetscInt point = points[2 * p]; 7086 const PetscInt *perm = perms ? perms[p] : NULL; 7087 const PetscScalar *flip = flips ? flips[p] : NULL; 7088 PetscCall(PetscSectionGetDof(section, point, &dof)); 7089 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7090 } 7091 break; 7092 case ADD_VALUES: 7093 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7094 const PetscInt point = points[2 * p]; 7095 const PetscInt *perm = perms ? perms[p] : NULL; 7096 const PetscScalar *flip = flips ? flips[p] : NULL; 7097 PetscCall(PetscSectionGetDof(section, point, &dof)); 7098 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7099 } 7100 break; 7101 case ADD_ALL_VALUES: 7102 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7103 const PetscInt point = points[2 * p]; 7104 const PetscInt *perm = perms ? perms[p] : NULL; 7105 const PetscScalar *flip = flips ? flips[p] : NULL; 7106 PetscCall(PetscSectionGetDof(section, point, &dof)); 7107 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7108 } 7109 break; 7110 case ADD_BC_VALUES: 7111 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7112 const PetscInt point = points[2 * p]; 7113 const PetscInt *perm = perms ? perms[p] : NULL; 7114 const PetscScalar *flip = flips ? flips[p] : NULL; 7115 PetscCall(PetscSectionGetDof(section, point, &dof)); 7116 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7117 } 7118 break; 7119 default: 7120 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7121 } 7122 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7123 } 7124 /* Cleanup points */ 7125 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7126 /* Cleanup array */ 7127 PetscCall(VecRestoreArray(v, &array)); 7128 PetscFunctionReturn(PETSC_SUCCESS); 7129 } 7130 7131 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7132 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7133 { 7134 PetscFunctionBegin; 7135 *contains = PETSC_TRUE; 7136 if (label) { 7137 PetscInt fdof; 7138 7139 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7140 if (!*contains) { 7141 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7142 *offset += fdof; 7143 PetscFunctionReturn(PETSC_SUCCESS); 7144 } 7145 } 7146 PetscFunctionReturn(PETSC_SUCCESS); 7147 } 7148 7149 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7150 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt labelId, const PetscScalar values[], InsertMode mode) 7151 { 7152 PetscSection clSection; 7153 IS clPoints; 7154 PetscScalar *array; 7155 PetscInt *points = NULL; 7156 const PetscInt *clp; 7157 PetscInt numFields, numPoints, p; 7158 PetscInt offset = 0, f; 7159 7160 PetscFunctionBeginHot; 7161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7162 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7163 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7164 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7165 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7166 /* Get points */ 7167 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7168 /* Get array */ 7169 PetscCall(VecGetArray(v, &array)); 7170 /* Get values */ 7171 for (f = 0; f < numFields; ++f) { 7172 const PetscInt **perms = NULL; 7173 const PetscScalar **flips = NULL; 7174 PetscBool contains; 7175 7176 if (!fieldActive[f]) { 7177 for (p = 0; p < numPoints * 2; p += 2) { 7178 PetscInt fdof; 7179 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7180 offset += fdof; 7181 } 7182 continue; 7183 } 7184 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7185 switch (mode) { 7186 case INSERT_VALUES: 7187 for (p = 0; p < numPoints; p++) { 7188 const PetscInt point = points[2 * p]; 7189 const PetscInt *perm = perms ? perms[p] : NULL; 7190 const PetscScalar *flip = flips ? flips[p] : NULL; 7191 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7192 if (!contains) continue; 7193 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7194 } 7195 break; 7196 case INSERT_ALL_VALUES: 7197 for (p = 0; p < numPoints; p++) { 7198 const PetscInt point = points[2 * p]; 7199 const PetscInt *perm = perms ? perms[p] : NULL; 7200 const PetscScalar *flip = flips ? flips[p] : NULL; 7201 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7202 if (!contains) continue; 7203 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7204 } 7205 break; 7206 case INSERT_BC_VALUES: 7207 for (p = 0; p < numPoints; p++) { 7208 const PetscInt point = points[2 * p]; 7209 const PetscInt *perm = perms ? perms[p] : NULL; 7210 const PetscScalar *flip = flips ? flips[p] : NULL; 7211 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7212 if (!contains) continue; 7213 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7214 } 7215 break; 7216 case ADD_VALUES: 7217 for (p = 0; p < numPoints; p++) { 7218 const PetscInt point = points[2 * p]; 7219 const PetscInt *perm = perms ? perms[p] : NULL; 7220 const PetscScalar *flip = flips ? flips[p] : NULL; 7221 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7222 if (!contains) continue; 7223 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7224 } 7225 break; 7226 case ADD_ALL_VALUES: 7227 for (p = 0; p < numPoints; p++) { 7228 const PetscInt point = points[2 * p]; 7229 const PetscInt *perm = perms ? perms[p] : NULL; 7230 const PetscScalar *flip = flips ? flips[p] : NULL; 7231 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7232 if (!contains) continue; 7233 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7234 } 7235 break; 7236 default: 7237 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7238 } 7239 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7240 } 7241 /* Cleanup points */ 7242 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7243 /* Cleanup array */ 7244 PetscCall(VecRestoreArray(v, &array)); 7245 PetscFunctionReturn(PETSC_SUCCESS); 7246 } 7247 7248 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7249 { 7250 PetscMPIInt rank; 7251 PetscInt i, j; 7252 7253 PetscFunctionBegin; 7254 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7255 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7256 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7257 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7258 numCIndices = numCIndices ? numCIndices : numRIndices; 7259 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7260 for (i = 0; i < numRIndices; i++) { 7261 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7262 for (j = 0; j < numCIndices; j++) { 7263 #if defined(PETSC_USE_COMPLEX) 7264 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7265 #else 7266 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7267 #endif 7268 } 7269 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7270 } 7271 PetscFunctionReturn(PETSC_SUCCESS); 7272 } 7273 7274 /* 7275 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7276 7277 Input Parameters: 7278 + section - The section for this data layout 7279 . islocal - Is the section (and thus indices being requested) local or global? 7280 . point - The point contributing dofs with these indices 7281 . off - The global offset of this point 7282 . loff - The local offset of each field 7283 . setBC - The flag determining whether to include indices of boundary values 7284 . perm - A permutation of the dofs on this point, or NULL 7285 - indperm - A permutation of the entire indices array, or NULL 7286 7287 Output Parameter: 7288 . indices - Indices for dofs on this point 7289 7290 Level: developer 7291 7292 Note: The indices could be local or global, depending on the value of 'off'. 7293 */ 7294 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7295 { 7296 PetscInt dof; /* The number of unknowns on this point */ 7297 PetscInt cdof; /* The number of constraints on this point */ 7298 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7299 PetscInt cind = 0, k; 7300 7301 PetscFunctionBegin; 7302 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7303 PetscCall(PetscSectionGetDof(section, point, &dof)); 7304 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7305 if (!cdof || setBC) { 7306 for (k = 0; k < dof; ++k) { 7307 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7308 const PetscInt ind = indperm ? indperm[preind] : preind; 7309 7310 indices[ind] = off + k; 7311 } 7312 } else { 7313 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7314 for (k = 0; k < dof; ++k) { 7315 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7316 const PetscInt ind = indperm ? indperm[preind] : preind; 7317 7318 if ((cind < cdof) && (k == cdofs[cind])) { 7319 /* Insert check for returning constrained indices */ 7320 indices[ind] = -(off + k + 1); 7321 ++cind; 7322 } else { 7323 indices[ind] = off + k - (islocal ? 0 : cind); 7324 } 7325 } 7326 } 7327 *loff += dof; 7328 PetscFunctionReturn(PETSC_SUCCESS); 7329 } 7330 7331 /* 7332 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7333 7334 Input Parameters: 7335 + section - a section (global or local) 7336 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7337 . point - point within section 7338 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7339 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7340 . setBC - identify constrained (boundary condition) points via involution. 7341 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7342 . permsoff - offset 7343 - indperm - index permutation 7344 7345 Output Parameter: 7346 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7347 . indices - array to hold indices (as defined by section) of each dof associated with point 7348 7349 Notes: 7350 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7351 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7352 in the local vector. 7353 7354 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7355 significant). It is invalid to call with a global section and setBC=true. 7356 7357 Developer Note: 7358 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7359 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7360 offset could be obtained from the section instead of passing it explicitly as we do now. 7361 7362 Example: 7363 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7364 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7365 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7366 The global vector does not store constrained dofs, so when this function returns global indices, say {110, -112, 111}, the value of -112 is an arbitrary flag that should not be interpreted beyond its sign. 7367 7368 Level: developer 7369 */ 7370 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7371 { 7372 PetscInt numFields, foff, f; 7373 7374 PetscFunctionBegin; 7375 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7376 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7377 for (f = 0, foff = 0; f < numFields; ++f) { 7378 PetscInt fdof, cfdof; 7379 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7380 PetscInt cind = 0, b; 7381 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7382 7383 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7384 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7385 if (!cfdof || setBC) { 7386 for (b = 0; b < fdof; ++b) { 7387 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7388 const PetscInt ind = indperm ? indperm[preind] : preind; 7389 7390 indices[ind] = off + foff + b; 7391 } 7392 } else { 7393 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7394 for (b = 0; b < fdof; ++b) { 7395 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7396 const PetscInt ind = indperm ? indperm[preind] : preind; 7397 7398 if ((cind < cfdof) && (b == fcdofs[cind])) { 7399 indices[ind] = -(off + foff + b + 1); 7400 ++cind; 7401 } else { 7402 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7403 } 7404 } 7405 } 7406 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7407 foffs[f] += fdof; 7408 } 7409 PetscFunctionReturn(PETSC_SUCCESS); 7410 } 7411 7412 /* 7413 This version believes the globalSection offsets for each field, rather than just the point offset 7414 7415 . foffs - The offset into 'indices' for each field, since it is segregated by field 7416 7417 Notes: 7418 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7419 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7420 */ 7421 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7422 { 7423 PetscInt numFields, foff, f; 7424 7425 PetscFunctionBegin; 7426 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7427 for (f = 0; f < numFields; ++f) { 7428 PetscInt fdof, cfdof; 7429 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7430 PetscInt cind = 0, b; 7431 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7432 7433 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7434 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7435 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7436 if (!cfdof) { 7437 for (b = 0; b < fdof; ++b) { 7438 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7439 const PetscInt ind = indperm ? indperm[preind] : preind; 7440 7441 indices[ind] = foff + b; 7442 } 7443 } else { 7444 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7445 for (b = 0; b < fdof; ++b) { 7446 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7447 const PetscInt ind = indperm ? indperm[preind] : preind; 7448 7449 if ((cind < cfdof) && (b == fcdofs[cind])) { 7450 indices[ind] = -(foff + b + 1); 7451 ++cind; 7452 } else { 7453 indices[ind] = foff + b - cind; 7454 } 7455 } 7456 } 7457 foffs[f] += fdof; 7458 } 7459 PetscFunctionReturn(PETSC_SUCCESS); 7460 } 7461 7462 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7463 { 7464 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7465 7466 PetscFunctionBegin; 7467 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7468 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7469 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7470 for (PetscInt p = 0; p < nPoints; p++) { 7471 PetscInt b = pnts[2 * p]; 7472 PetscInt bSecDof = 0, bOff; 7473 PetscInt cSecDof = 0; 7474 PetscSection indices_section; 7475 7476 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7477 if (!bSecDof) continue; 7478 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7479 indices_section = cSecDof > 0 ? cSec : section; 7480 if (numFields) { 7481 PetscInt fStart[32], fEnd[32]; 7482 7483 fStart[0] = 0; 7484 fEnd[0] = 0; 7485 for (PetscInt f = 0; f < numFields; f++) { 7486 PetscInt fDof = 0; 7487 7488 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7489 fStart[f + 1] = fStart[f] + fDof; 7490 fEnd[f + 1] = fStart[f + 1]; 7491 } 7492 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7493 // only apply permutations on one side 7494 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7495 for (PetscInt f = 0; f < numFields; f++) { 7496 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7497 } 7498 } else { 7499 PetscInt bEnd = 0; 7500 7501 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7502 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7503 7504 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7505 } 7506 } 7507 PetscFunctionReturn(PETSC_SUCCESS); 7508 } 7509 7510 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[]) 7511 { 7512 Mat cMat; 7513 PetscSection aSec, cSec; 7514 IS aIS; 7515 PetscInt aStart = -1, aEnd = -1; 7516 PetscInt sStart = -1, sEnd = -1; 7517 PetscInt cStart = -1, cEnd = -1; 7518 const PetscInt *anchors; 7519 PetscInt numFields, f, p; 7520 PetscInt newNumPoints = 0, newNumIndices = 0; 7521 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7522 PetscInt oldOffsets[32]; 7523 PetscInt newOffsets[32]; 7524 PetscInt oldOffsetsCopy[32]; 7525 PetscInt newOffsetsCopy[32]; 7526 PetscScalar *modMat = NULL; 7527 PetscBool anyConstrained = PETSC_FALSE; 7528 7529 PetscFunctionBegin; 7530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7531 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7532 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7533 7534 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7535 /* if there are point-to-point constraints */ 7536 if (aSec) { 7537 PetscCall(PetscArrayzero(newOffsets, 32)); 7538 PetscCall(PetscArrayzero(oldOffsets, 32)); 7539 PetscCall(ISGetIndices(aIS, &anchors)); 7540 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7541 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7542 /* figure out how many points are going to be in the new element matrix 7543 * (we allow double counting, because it's all just going to be summed 7544 * into the global matrix anyway) */ 7545 for (p = 0; p < 2 * numPoints; p += 2) { 7546 PetscInt b = points[p]; 7547 PetscInt bDof = 0, bSecDof = 0; 7548 7549 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7550 if (!bSecDof) continue; 7551 7552 for (PetscInt f = 0; f < numFields; f++) { 7553 PetscInt fDof = 0; 7554 7555 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7556 oldOffsets[f + 1] += fDof; 7557 } 7558 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7559 if (bDof) { 7560 /* this point is constrained */ 7561 /* it is going to be replaced by its anchors */ 7562 PetscInt bOff, q; 7563 7564 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7565 for (q = 0; q < bDof; q++) { 7566 PetscInt a = anchors[bOff + q]; 7567 PetscInt aDof = 0; 7568 7569 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7570 if (aDof) { 7571 anyConstrained = PETSC_TRUE; 7572 newNumPoints += 1; 7573 } 7574 newNumIndices += aDof; 7575 for (f = 0; f < numFields; ++f) { 7576 PetscInt fDof = 0; 7577 7578 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7579 newOffsets[f + 1] += fDof; 7580 } 7581 } 7582 } else { 7583 /* this point is not constrained */ 7584 newNumPoints++; 7585 newNumIndices += bSecDof; 7586 for (f = 0; f < numFields; ++f) { 7587 PetscInt fDof; 7588 7589 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7590 newOffsets[f + 1] += fDof; 7591 } 7592 } 7593 } 7594 } 7595 if (!anyConstrained) { 7596 if (outNumPoints) *outNumPoints = 0; 7597 if (outNumIndices) *outNumIndices = 0; 7598 if (outPoints) *outPoints = NULL; 7599 if (outMat) *outMat = NULL; 7600 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7601 PetscFunctionReturn(PETSC_SUCCESS); 7602 } 7603 7604 if (outNumPoints) *outNumPoints = newNumPoints; 7605 if (outNumIndices) *outNumIndices = newNumIndices; 7606 7607 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7608 for (f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7609 7610 if (!outPoints && !outMat) { 7611 if (offsets) { 7612 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7613 } 7614 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7615 PetscFunctionReturn(PETSC_SUCCESS); 7616 } 7617 7618 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7619 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7620 7621 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7622 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7623 7624 /* output arrays */ 7625 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7626 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7627 7628 // get the new Points 7629 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7630 PetscInt b = points[2 * p]; 7631 PetscInt bDof = 0, bSecDof = 0, bOff; 7632 7633 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7634 if (!bSecDof) continue; 7635 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7636 if (bDof) { 7637 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7638 for (PetscInt q = 0; q < bDof; q++) { 7639 PetscInt a = anchors[bOff + q], aDof = 0; 7640 7641 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7642 if (aDof) { 7643 newPoints[2 * newP] = a; 7644 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7645 newP++; 7646 } 7647 } 7648 } else { 7649 newPoints[2 * newP] = b; 7650 newPoints[2 * newP + 1] = points[2 * p + 1]; 7651 newP++; 7652 } 7653 } 7654 7655 if (outMat) { 7656 PetscScalar *tmpMat; 7657 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7658 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7659 7660 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7661 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7662 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7663 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7664 7665 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7666 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7667 7668 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7669 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7670 7671 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7672 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7673 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7674 // for each field, insert the anchor modification into modMat 7675 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7676 PetscInt fStart = oldOffsets[f]; 7677 PetscInt fNewStart = newOffsets[f]; 7678 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7679 PetscInt b = points[2 * p]; 7680 PetscInt bDof = 0, bSecDof = 0, bOff; 7681 7682 if (b >= sStart && b < sEnd) { 7683 if (numFields) { 7684 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7685 } else { 7686 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7687 } 7688 } 7689 if (!bSecDof) continue; 7690 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7691 if (bDof) { 7692 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7693 for (PetscInt q = 0; q < bDof; q++, newP++) { 7694 PetscInt a = anchors[bOff + q], aDof = 0; 7695 7696 if (a >= sStart && a < sEnd) { 7697 if (numFields) { 7698 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7699 } else { 7700 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7701 } 7702 } 7703 if (aDof) { 7704 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7705 for (PetscInt d = 0; d < bSecDof; d++) { 7706 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7707 } 7708 } 7709 oNew += aDof; 7710 } 7711 } else { 7712 // Insert the identity matrix in this block 7713 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7714 oNew += bSecDof; 7715 newP++; 7716 } 7717 o += bSecDof; 7718 } 7719 } 7720 7721 *outMat = modMat; 7722 7723 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7724 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7725 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7726 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7727 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7728 } 7729 PetscCall(ISRestoreIndices(aIS, &anchors)); 7730 7731 /* output */ 7732 if (outPoints) { 7733 *outPoints = newPoints; 7734 } else { 7735 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7736 } 7737 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7738 PetscFunctionReturn(PETSC_SUCCESS); 7739 } 7740 7741 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) 7742 { 7743 PetscScalar *modMat = NULL; 7744 PetscInt newNumIndices = -1; 7745 7746 PetscFunctionBegin; 7747 /* 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. 7748 modMat is that matrix C */ 7749 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7750 if (outNumIndices) *outNumIndices = newNumIndices; 7751 if (modMat) { 7752 const PetscScalar *newValues = values; 7753 7754 if (multiplyRight) { 7755 PetscScalar *newNewValues = NULL; 7756 PetscBLASInt M = newNumIndices; 7757 PetscBLASInt N = numRows; 7758 PetscBLASInt K = numIndices; 7759 PetscScalar a = 1.0, b = 0.0; 7760 7761 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); 7762 7763 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7764 // row-major to column-major conversion, right multiplication becomes left multiplication 7765 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7766 7767 numCols = newNumIndices; 7768 newValues = newNewValues; 7769 } 7770 7771 if (multiplyLeft) { 7772 PetscScalar *newNewValues = NULL; 7773 PetscBLASInt M = numCols; 7774 PetscBLASInt N = newNumIndices; 7775 PetscBLASInt K = numIndices; 7776 PetscScalar a = 1.0, b = 0.0; 7777 7778 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); 7779 7780 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7781 // row-major to column-major conversion, left multiplication becomes right multiplication 7782 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7783 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7784 newValues = newNewValues; 7785 } 7786 *outValues = (PetscScalar *)newValues; 7787 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7788 } 7789 PetscFunctionReturn(PETSC_SUCCESS); 7790 } 7791 7792 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) 7793 { 7794 PetscFunctionBegin; 7795 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7796 PetscFunctionReturn(PETSC_SUCCESS); 7797 } 7798 7799 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7800 { 7801 /* Closure ordering */ 7802 PetscSection clSection; 7803 IS clPoints; 7804 const PetscInt *clp; 7805 PetscInt *points; 7806 PetscInt Ncl, Ni = 0; 7807 7808 PetscFunctionBeginHot; 7809 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7810 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7811 PetscInt dof; 7812 7813 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7814 Ni += dof; 7815 } 7816 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7817 *closureSize = Ni; 7818 PetscFunctionReturn(PETSC_SUCCESS); 7819 } 7820 7821 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) 7822 { 7823 /* Closure ordering */ 7824 PetscSection clSection; 7825 IS clPoints; 7826 const PetscInt *clp; 7827 PetscInt *points; 7828 const PetscInt *clperm = NULL; 7829 /* Dof permutation and sign flips */ 7830 const PetscInt **perms[32] = {NULL}; 7831 const PetscScalar **flips[32] = {NULL}; 7832 PetscScalar *valCopy = NULL; 7833 /* Hanging node constraints */ 7834 PetscInt *pointsC = NULL; 7835 PetscScalar *valuesC = NULL; 7836 PetscInt NclC, NiC; 7837 7838 PetscInt *idx; 7839 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7840 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7841 PetscInt idxStart, idxEnd; 7842 PetscInt nRows, nCols; 7843 7844 PetscFunctionBeginHot; 7845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7846 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7847 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7848 PetscAssertPointer(numRows, 6); 7849 PetscAssertPointer(numCols, 7); 7850 if (indices) PetscAssertPointer(indices, 8); 7851 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7852 if (values) PetscAssertPointer(values, 10); 7853 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7854 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7855 PetscCall(PetscArrayzero(offsets, 32)); 7856 /* 1) Get points in closure */ 7857 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7858 if (useClPerm) { 7859 PetscInt depth, clsize; 7860 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7861 for (clsize = 0, p = 0; p < Ncl; p++) { 7862 PetscInt dof; 7863 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7864 clsize += dof; 7865 } 7866 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7867 } 7868 /* 2) Get number of indices on these points and field offsets from section */ 7869 for (p = 0; p < Ncl * 2; p += 2) { 7870 PetscInt dof, fdof; 7871 7872 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7873 for (f = 0; f < Nf; ++f) { 7874 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7875 offsets[f + 1] += fdof; 7876 } 7877 Ni += dof; 7878 } 7879 if (*numRows == -1) *numRows = Ni; 7880 if (*numCols == -1) *numCols = Ni; 7881 nRows = *numRows; 7882 nCols = *numCols; 7883 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7884 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7885 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7886 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7887 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7888 for (f = 0; f < PetscMax(1, Nf); ++f) { 7889 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7890 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7891 /* may need to apply sign changes to the element matrix */ 7892 if (values && flips[f]) { 7893 PetscInt foffset = offsets[f]; 7894 7895 for (p = 0; p < Ncl; ++p) { 7896 PetscInt pnt = points[2 * p], fdof; 7897 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7898 7899 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7900 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7901 if (flip) { 7902 PetscInt i, j, k; 7903 7904 if (!valCopy) { 7905 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7906 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7907 *values = valCopy; 7908 } 7909 for (i = 0; i < fdof; ++i) { 7910 PetscScalar fval = flip[i]; 7911 7912 if (multiplyRight) { 7913 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 7914 } 7915 if (multiplyLeft) { 7916 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 7917 } 7918 } 7919 } 7920 foffset += fdof; 7921 } 7922 } 7923 } 7924 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7925 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 7926 if (NclC) { 7927 if (multiplyRight) { *numCols = nCols = NiC; } 7928 if (multiplyLeft) { *numRows = nRows = NiC; } 7929 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7930 for (f = 0; f < PetscMax(1, Nf); ++f) { 7931 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7932 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7933 } 7934 for (f = 0; f < PetscMax(1, Nf); ++f) { 7935 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7936 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7937 } 7938 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7939 Ncl = NclC; 7940 Ni = NiC; 7941 points = pointsC; 7942 if (values) *values = valuesC; 7943 } 7944 /* 5) Calculate indices */ 7945 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7946 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 7947 if (Nf) { 7948 PetscInt idxOff; 7949 PetscBool useFieldOffsets; 7950 7951 if (outOffsets) { 7952 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7953 } 7954 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7955 if (useFieldOffsets) { 7956 for (p = 0; p < Ncl; ++p) { 7957 const PetscInt pnt = points[p * 2]; 7958 7959 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7960 } 7961 } else { 7962 for (p = 0; p < Ncl; ++p) { 7963 const PetscInt pnt = points[p * 2]; 7964 7965 if (pnt < idxStart || pnt >= idxEnd) continue; 7966 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7967 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7968 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7969 * global section. */ 7970 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7971 } 7972 } 7973 } else { 7974 PetscInt off = 0, idxOff; 7975 7976 for (p = 0; p < Ncl; ++p) { 7977 const PetscInt pnt = points[p * 2]; 7978 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7979 7980 if (pnt < idxStart || pnt >= idxEnd) continue; 7981 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7982 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7983 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7984 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7985 } 7986 } 7987 /* 6) Cleanup */ 7988 for (f = 0; f < PetscMax(1, Nf); ++f) { 7989 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7990 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7991 } 7992 if (NclC) { 7993 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7994 } else { 7995 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7996 } 7997 7998 if (indices) *indices = idx; 7999 PetscFunctionReturn(PETSC_SUCCESS); 8000 } 8001 8002 /*@C 8003 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8004 8005 Not collective 8006 8007 Input Parameters: 8008 + dm - The `DM` 8009 . section - The `PetscSection` describing the points (a local section) 8010 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8011 . point - The point defining the closure 8012 - useClPerm - Use the closure point permutation if available 8013 8014 Output Parameters: 8015 + numIndices - The number of dof indices in the closure of point with the input sections 8016 . indices - The dof indices 8017 . outOffsets - Array to write the field offsets into, or `NULL` 8018 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8019 8020 Level: advanced 8021 8022 Notes: 8023 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 8024 8025 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8026 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8027 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8028 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8029 indices (with the above semantics) are implied. 8030 8031 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8032 `PetscSection`, `DMGetGlobalSection()` 8033 @*/ 8034 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8035 { 8036 PetscInt numRows = -1, numCols = -1; 8037 8038 PetscFunctionBeginHot; 8039 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8040 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8041 *numIndices = numRows; 8042 PetscFunctionReturn(PETSC_SUCCESS); 8043 } 8044 8045 /*@C 8046 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8047 8048 Not collective 8049 8050 Input Parameters: 8051 + dm - The `DM` 8052 . section - The `PetscSection` describing the points (a local section) 8053 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8054 . point - The point defining the closure 8055 - useClPerm - Use the closure point permutation if available 8056 8057 Output Parameters: 8058 + numIndices - The number of dof indices in the closure of point with the input sections 8059 . indices - The dof indices 8060 . outOffsets - Array to write the field offsets into, or `NULL` 8061 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8062 8063 Level: advanced 8064 8065 Notes: 8066 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8067 8068 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8069 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8070 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8071 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8072 indices (with the above semantics) are implied. 8073 8074 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8075 @*/ 8076 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8077 { 8078 PetscFunctionBegin; 8079 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8080 PetscAssertPointer(indices, 7); 8081 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8082 PetscFunctionReturn(PETSC_SUCCESS); 8083 } 8084 8085 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8086 { 8087 DM_Plex *mesh = (DM_Plex *)dm->data; 8088 PetscInt *indices; 8089 PetscInt numIndices; 8090 const PetscScalar *valuesOrig = values; 8091 PetscErrorCode ierr; 8092 8093 PetscFunctionBegin; 8094 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8095 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8096 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8097 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8098 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8099 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8100 8101 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8102 8103 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8104 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8105 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8106 if (ierr) { 8107 PetscMPIInt rank; 8108 8109 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8110 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8111 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8112 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8113 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8114 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8115 } 8116 if (mesh->printFEM > 1) { 8117 PetscInt i; 8118 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8119 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8120 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8121 } 8122 8123 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8124 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8125 PetscFunctionReturn(PETSC_SUCCESS); 8126 } 8127 8128 /*@C 8129 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8130 8131 Not collective 8132 8133 Input Parameters: 8134 + dm - The `DM` 8135 . section - The section describing the layout in `v`, or `NULL` to use the default section 8136 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8137 . A - The matrix 8138 . point - The point in the `DM` 8139 . values - The array of values 8140 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8141 8142 Level: intermediate 8143 8144 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8145 @*/ 8146 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8147 { 8148 PetscFunctionBegin; 8149 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8150 PetscFunctionReturn(PETSC_SUCCESS); 8151 } 8152 8153 /*@C 8154 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8155 8156 Not collective 8157 8158 Input Parameters: 8159 + dmRow - The `DM` for the row fields 8160 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8161 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8162 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8163 . dmCol - The `DM` for the column fields 8164 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8165 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8166 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8167 . A - The matrix 8168 . point - The point in the `DM` 8169 . values - The array of values 8170 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8171 8172 Level: intermediate 8173 8174 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8175 @*/ 8176 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) 8177 { 8178 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8179 PetscInt *indicesRow, *indicesCol; 8180 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8181 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8182 8183 PetscErrorCode ierr; 8184 8185 PetscFunctionBegin; 8186 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8187 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8188 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8189 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8190 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8191 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8192 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8193 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8194 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8195 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8196 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8197 8198 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8199 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8200 valuesV1 = valuesV0; 8201 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8202 valuesV2 = valuesV1; 8203 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8204 8205 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8206 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8207 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8208 if (ierr) { 8209 PetscMPIInt rank; 8210 8211 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8212 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8213 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8214 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8215 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8216 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8217 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8218 } 8219 8220 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8221 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8222 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8223 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8224 PetscFunctionReturn(PETSC_SUCCESS); 8225 } 8226 8227 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8228 { 8229 DM_Plex *mesh = (DM_Plex *)dmf->data; 8230 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8231 PetscInt *cpoints = NULL; 8232 PetscInt *findices, *cindices; 8233 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8234 PetscInt foffsets[32], coffsets[32]; 8235 DMPolytopeType ct; 8236 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8237 PetscErrorCode ierr; 8238 8239 PetscFunctionBegin; 8240 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8241 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8242 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8243 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8244 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8245 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8246 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8247 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8248 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8249 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8250 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8251 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8252 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8253 PetscCall(PetscArrayzero(foffsets, 32)); 8254 PetscCall(PetscArrayzero(coffsets, 32)); 8255 /* Column indices */ 8256 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8257 maxFPoints = numCPoints; 8258 /* Compress out points not in the section */ 8259 /* TODO: Squeeze out points with 0 dof as well */ 8260 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8261 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8262 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8263 cpoints[q * 2] = cpoints[p]; 8264 cpoints[q * 2 + 1] = cpoints[p + 1]; 8265 ++q; 8266 } 8267 } 8268 numCPoints = q; 8269 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8270 PetscInt fdof; 8271 8272 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8273 if (!dof) continue; 8274 for (f = 0; f < numFields; ++f) { 8275 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8276 coffsets[f + 1] += fdof; 8277 } 8278 numCIndices += dof; 8279 } 8280 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8281 /* Row indices */ 8282 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8283 { 8284 DMPlexTransform tr; 8285 DMPolytopeType *rct; 8286 PetscInt *rsize, *rcone, *rornt, Nt; 8287 8288 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8289 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8290 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8291 numSubcells = rsize[Nt - 1]; 8292 PetscCall(DMPlexTransformDestroy(&tr)); 8293 } 8294 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8295 for (r = 0, q = 0; r < numSubcells; ++r) { 8296 /* TODO Map from coarse to fine cells */ 8297 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8298 /* Compress out points not in the section */ 8299 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8300 for (p = 0; p < numFPoints * 2; p += 2) { 8301 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8302 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8303 if (!dof) continue; 8304 for (s = 0; s < q; ++s) 8305 if (fpoints[p] == ftotpoints[s * 2]) break; 8306 if (s < q) continue; 8307 ftotpoints[q * 2] = fpoints[p]; 8308 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8309 ++q; 8310 } 8311 } 8312 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8313 } 8314 numFPoints = q; 8315 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8316 PetscInt fdof; 8317 8318 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8319 if (!dof) continue; 8320 for (f = 0; f < numFields; ++f) { 8321 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8322 foffsets[f + 1] += fdof; 8323 } 8324 numFIndices += dof; 8325 } 8326 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8327 8328 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8329 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8330 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8331 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8332 if (numFields) { 8333 const PetscInt **permsF[32] = {NULL}; 8334 const PetscInt **permsC[32] = {NULL}; 8335 8336 for (f = 0; f < numFields; f++) { 8337 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8338 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8339 } 8340 for (p = 0; p < numFPoints; p++) { 8341 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8342 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8343 } 8344 for (p = 0; p < numCPoints; p++) { 8345 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8346 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8347 } 8348 for (f = 0; f < numFields; f++) { 8349 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8350 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8351 } 8352 } else { 8353 const PetscInt **permsF = NULL; 8354 const PetscInt **permsC = NULL; 8355 8356 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8357 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8358 for (p = 0, off = 0; p < numFPoints; p++) { 8359 const PetscInt *perm = permsF ? permsF[p] : NULL; 8360 8361 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8362 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8363 } 8364 for (p = 0, off = 0; p < numCPoints; p++) { 8365 const PetscInt *perm = permsC ? permsC[p] : NULL; 8366 8367 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8368 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8369 } 8370 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8371 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8372 } 8373 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8374 /* TODO: flips */ 8375 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8376 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8377 if (ierr) { 8378 PetscMPIInt rank; 8379 8380 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8381 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8382 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8383 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8384 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8385 } 8386 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8387 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8388 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8389 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8390 PetscFunctionReturn(PETSC_SUCCESS); 8391 } 8392 8393 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8394 { 8395 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8396 PetscInt *cpoints = NULL; 8397 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8398 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8399 DMPolytopeType ct; 8400 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8401 8402 PetscFunctionBegin; 8403 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8404 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8405 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8406 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8407 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8408 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8409 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8410 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8411 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8412 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8413 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8414 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8415 /* Column indices */ 8416 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8417 maxFPoints = numCPoints; 8418 /* Compress out points not in the section */ 8419 /* TODO: Squeeze out points with 0 dof as well */ 8420 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8421 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8422 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8423 cpoints[q * 2] = cpoints[p]; 8424 cpoints[q * 2 + 1] = cpoints[p + 1]; 8425 ++q; 8426 } 8427 } 8428 numCPoints = q; 8429 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8430 PetscInt fdof; 8431 8432 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8433 if (!dof) continue; 8434 for (f = 0; f < numFields; ++f) { 8435 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8436 coffsets[f + 1] += fdof; 8437 } 8438 numCIndices += dof; 8439 } 8440 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8441 /* Row indices */ 8442 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8443 { 8444 DMPlexTransform tr; 8445 DMPolytopeType *rct; 8446 PetscInt *rsize, *rcone, *rornt, Nt; 8447 8448 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8449 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8450 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8451 numSubcells = rsize[Nt - 1]; 8452 PetscCall(DMPlexTransformDestroy(&tr)); 8453 } 8454 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8455 for (r = 0, q = 0; r < numSubcells; ++r) { 8456 /* TODO Map from coarse to fine cells */ 8457 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8458 /* Compress out points not in the section */ 8459 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8460 for (p = 0; p < numFPoints * 2; p += 2) { 8461 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8462 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8463 if (!dof) continue; 8464 for (s = 0; s < q; ++s) 8465 if (fpoints[p] == ftotpoints[s * 2]) break; 8466 if (s < q) continue; 8467 ftotpoints[q * 2] = fpoints[p]; 8468 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8469 ++q; 8470 } 8471 } 8472 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8473 } 8474 numFPoints = q; 8475 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8476 PetscInt fdof; 8477 8478 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8479 if (!dof) continue; 8480 for (f = 0; f < numFields; ++f) { 8481 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8482 foffsets[f + 1] += fdof; 8483 } 8484 numFIndices += dof; 8485 } 8486 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8487 8488 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8489 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8490 if (numFields) { 8491 const PetscInt **permsF[32] = {NULL}; 8492 const PetscInt **permsC[32] = {NULL}; 8493 8494 for (f = 0; f < numFields; f++) { 8495 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8496 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8497 } 8498 for (p = 0; p < numFPoints; p++) { 8499 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8500 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8501 } 8502 for (p = 0; p < numCPoints; p++) { 8503 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8504 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8505 } 8506 for (f = 0; f < numFields; f++) { 8507 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8508 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8509 } 8510 } else { 8511 const PetscInt **permsF = NULL; 8512 const PetscInt **permsC = NULL; 8513 8514 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8515 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8516 for (p = 0, off = 0; p < numFPoints; p++) { 8517 const PetscInt *perm = permsF ? permsF[p] : NULL; 8518 8519 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8520 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8521 } 8522 for (p = 0, off = 0; p < numCPoints; p++) { 8523 const PetscInt *perm = permsC ? permsC[p] : NULL; 8524 8525 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8526 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8527 } 8528 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8529 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8530 } 8531 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8532 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8533 PetscFunctionReturn(PETSC_SUCCESS); 8534 } 8535 8536 /*@C 8537 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8538 8539 Input Parameter: 8540 . dm - The `DMPLEX` object 8541 8542 Output Parameter: 8543 . cellHeight - The height of a cell 8544 8545 Level: developer 8546 8547 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8548 @*/ 8549 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8550 { 8551 DM_Plex *mesh = (DM_Plex *)dm->data; 8552 8553 PetscFunctionBegin; 8554 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8555 PetscAssertPointer(cellHeight, 2); 8556 *cellHeight = mesh->vtkCellHeight; 8557 PetscFunctionReturn(PETSC_SUCCESS); 8558 } 8559 8560 /*@C 8561 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8562 8563 Input Parameters: 8564 + dm - The `DMPLEX` object 8565 - cellHeight - The height of a cell 8566 8567 Level: developer 8568 8569 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8570 @*/ 8571 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8572 { 8573 DM_Plex *mesh = (DM_Plex *)dm->data; 8574 8575 PetscFunctionBegin; 8576 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8577 mesh->vtkCellHeight = cellHeight; 8578 PetscFunctionReturn(PETSC_SUCCESS); 8579 } 8580 8581 /*@ 8582 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8583 8584 Input Parameters: 8585 + dm - The `DMPLEX` object 8586 - ct - The `DMPolytopeType` of the cell 8587 8588 Output Parameters: 8589 + start - The first cell of this type, or `NULL` 8590 - end - The upper bound on this celltype, or `NULL` 8591 8592 Level: advanced 8593 8594 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8595 @*/ 8596 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8597 { 8598 DM_Plex *mesh = (DM_Plex *)dm->data; 8599 DMLabel label; 8600 PetscInt pStart, pEnd; 8601 8602 PetscFunctionBegin; 8603 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8604 if (start) { 8605 PetscAssertPointer(start, 3); 8606 *start = 0; 8607 } 8608 if (end) { 8609 PetscAssertPointer(end, 4); 8610 *end = 0; 8611 } 8612 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8613 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8614 if (mesh->tr) { 8615 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8616 } else { 8617 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8618 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8619 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8620 } 8621 PetscFunctionReturn(PETSC_SUCCESS); 8622 } 8623 8624 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8625 { 8626 PetscSection section, globalSection; 8627 PetscInt *numbers, p; 8628 8629 PetscFunctionBegin; 8630 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8631 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8632 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8633 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8634 PetscCall(PetscSectionSetUp(section)); 8635 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8636 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8637 for (p = pStart; p < pEnd; ++p) { 8638 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8639 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8640 else numbers[p - pStart] += shift; 8641 } 8642 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8643 if (globalSize) { 8644 PetscLayout layout; 8645 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8646 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8647 PetscCall(PetscLayoutDestroy(&layout)); 8648 } 8649 PetscCall(PetscSectionDestroy(§ion)); 8650 PetscCall(PetscSectionDestroy(&globalSection)); 8651 PetscFunctionReturn(PETSC_SUCCESS); 8652 } 8653 8654 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8655 { 8656 PetscInt cellHeight, cStart, cEnd; 8657 8658 PetscFunctionBegin; 8659 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8660 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8661 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8662 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8663 PetscFunctionReturn(PETSC_SUCCESS); 8664 } 8665 8666 /*@ 8667 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8668 8669 Input Parameter: 8670 . dm - The `DMPLEX` object 8671 8672 Output Parameter: 8673 . globalCellNumbers - Global cell numbers for all cells on this process 8674 8675 Level: developer 8676 8677 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8678 @*/ 8679 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8680 { 8681 DM_Plex *mesh = (DM_Plex *)dm->data; 8682 8683 PetscFunctionBegin; 8684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8685 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8686 *globalCellNumbers = mesh->globalCellNumbers; 8687 PetscFunctionReturn(PETSC_SUCCESS); 8688 } 8689 8690 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8691 { 8692 PetscInt vStart, vEnd; 8693 8694 PetscFunctionBegin; 8695 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8696 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8697 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8698 PetscFunctionReturn(PETSC_SUCCESS); 8699 } 8700 8701 /*@ 8702 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8703 8704 Input Parameter: 8705 . dm - The `DMPLEX` object 8706 8707 Output Parameter: 8708 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8709 8710 Level: developer 8711 8712 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8713 @*/ 8714 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8715 { 8716 DM_Plex *mesh = (DM_Plex *)dm->data; 8717 8718 PetscFunctionBegin; 8719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8720 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8721 *globalVertexNumbers = mesh->globalVertexNumbers; 8722 PetscFunctionReturn(PETSC_SUCCESS); 8723 } 8724 8725 /*@ 8726 DMPlexCreatePointNumbering - Create a global numbering for all points. 8727 8728 Collective 8729 8730 Input Parameter: 8731 . dm - The `DMPLEX` object 8732 8733 Output Parameter: 8734 . globalPointNumbers - Global numbers for all points on this process 8735 8736 Level: developer 8737 8738 Notes: 8739 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8740 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8741 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8742 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8743 8744 The partitioned mesh is 8745 ``` 8746 (2)--0--(3)--1--(4) (1)--0--(2) 8747 ``` 8748 and its global numbering is 8749 ``` 8750 (3)--0--(4)--1--(5)--2--(6) 8751 ``` 8752 Then the global numbering is provided as 8753 ``` 8754 [0] Number of indices in set 5 8755 [0] 0 0 8756 [0] 1 1 8757 [0] 2 3 8758 [0] 3 4 8759 [0] 4 -6 8760 [1] Number of indices in set 3 8761 [1] 0 2 8762 [1] 1 5 8763 [1] 2 6 8764 ``` 8765 8766 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8767 @*/ 8768 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8769 { 8770 IS nums[4]; 8771 PetscInt depths[4], gdepths[4], starts[4]; 8772 PetscInt depth, d, shift = 0; 8773 PetscBool empty = PETSC_FALSE; 8774 8775 PetscFunctionBegin; 8776 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8777 PetscCall(DMPlexGetDepth(dm, &depth)); 8778 // For unstratified meshes use dim instead of depth 8779 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8780 // If any stratum is empty, we must mark all empty 8781 for (d = 0; d <= depth; ++d) { 8782 PetscInt end; 8783 8784 depths[d] = depth - d; 8785 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8786 if (!(starts[d] - end)) empty = PETSC_TRUE; 8787 } 8788 if (empty) 8789 for (d = 0; d <= depth; ++d) { 8790 depths[d] = -1; 8791 starts[d] = -1; 8792 } 8793 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8794 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8795 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]); 8796 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8797 for (d = 0; d <= depth; ++d) { 8798 PetscInt pStart, pEnd, gsize; 8799 8800 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8801 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8802 shift += gsize; 8803 } 8804 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8805 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8806 PetscFunctionReturn(PETSC_SUCCESS); 8807 } 8808 8809 /*@ 8810 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8811 8812 Input Parameter: 8813 . dm - The `DMPLEX` object 8814 8815 Output Parameter: 8816 . ranks - The rank field 8817 8818 Options Database Key: 8819 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8820 8821 Level: intermediate 8822 8823 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8824 @*/ 8825 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8826 { 8827 DM rdm; 8828 PetscFE fe; 8829 PetscScalar *r; 8830 PetscMPIInt rank; 8831 DMPolytopeType ct; 8832 PetscInt dim, cStart, cEnd, c; 8833 PetscBool simplex; 8834 8835 PetscFunctionBeginUser; 8836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8837 PetscAssertPointer(ranks, 2); 8838 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8839 PetscCall(DMClone(dm, &rdm)); 8840 PetscCall(DMGetDimension(rdm, &dim)); 8841 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8842 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8843 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8844 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8845 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8846 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8847 PetscCall(PetscFEDestroy(&fe)); 8848 PetscCall(DMCreateDS(rdm)); 8849 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8850 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8851 PetscCall(VecGetArray(*ranks, &r)); 8852 for (c = cStart; c < cEnd; ++c) { 8853 PetscScalar *lr; 8854 8855 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8856 if (lr) *lr = rank; 8857 } 8858 PetscCall(VecRestoreArray(*ranks, &r)); 8859 PetscCall(DMDestroy(&rdm)); 8860 PetscFunctionReturn(PETSC_SUCCESS); 8861 } 8862 8863 /*@ 8864 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8865 8866 Input Parameters: 8867 + dm - The `DMPLEX` 8868 - label - The `DMLabel` 8869 8870 Output Parameter: 8871 . val - The label value field 8872 8873 Options Database Key: 8874 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8875 8876 Level: intermediate 8877 8878 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8879 @*/ 8880 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8881 { 8882 DM rdm, plex; 8883 Vec lval; 8884 PetscSection section; 8885 PetscFE fe; 8886 PetscScalar *v; 8887 PetscInt dim, pStart, pEnd, p, cStart; 8888 DMPolytopeType ct; 8889 char name[PETSC_MAX_PATH_LEN]; 8890 const char *lname, *prefix; 8891 8892 PetscFunctionBeginUser; 8893 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8894 PetscAssertPointer(label, 2); 8895 PetscAssertPointer(val, 3); 8896 PetscCall(DMClone(dm, &rdm)); 8897 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8898 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8899 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8900 PetscCall(DMDestroy(&plex)); 8901 PetscCall(DMGetDimension(rdm, &dim)); 8902 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8903 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8904 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8905 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8906 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8907 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8908 PetscCall(PetscFEDestroy(&fe)); 8909 PetscCall(DMCreateDS(rdm)); 8910 PetscCall(DMCreateGlobalVector(rdm, val)); 8911 PetscCall(DMCreateLocalVector(rdm, &lval)); 8912 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8913 PetscCall(DMGetLocalSection(rdm, §ion)); 8914 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8915 PetscCall(VecGetArray(lval, &v)); 8916 for (p = pStart; p < pEnd; ++p) { 8917 PetscInt cval, dof, off; 8918 8919 PetscCall(PetscSectionGetDof(section, p, &dof)); 8920 if (!dof) continue; 8921 PetscCall(DMLabelGetValue(label, p, &cval)); 8922 PetscCall(PetscSectionGetOffset(section, p, &off)); 8923 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 8924 } 8925 PetscCall(VecRestoreArray(lval, &v)); 8926 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 8927 PetscCall(VecDestroy(&lval)); 8928 PetscCall(DMDestroy(&rdm)); 8929 PetscFunctionReturn(PETSC_SUCCESS); 8930 } 8931 8932 /*@ 8933 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8934 8935 Input Parameter: 8936 . dm - The `DMPLEX` object 8937 8938 Level: developer 8939 8940 Notes: 8941 This is a useful diagnostic when creating meshes programmatically. 8942 8943 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8944 8945 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8946 @*/ 8947 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8948 { 8949 PetscSection coneSection, supportSection; 8950 const PetscInt *cone, *support; 8951 PetscInt coneSize, c, supportSize, s; 8952 PetscInt pStart, pEnd, p, pp, csize, ssize; 8953 PetscBool storagecheck = PETSC_TRUE; 8954 8955 PetscFunctionBegin; 8956 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8957 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8958 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8959 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8960 /* Check that point p is found in the support of its cone points, and vice versa */ 8961 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8962 for (p = pStart; p < pEnd; ++p) { 8963 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8964 PetscCall(DMPlexGetCone(dm, p, &cone)); 8965 for (c = 0; c < coneSize; ++c) { 8966 PetscBool dup = PETSC_FALSE; 8967 PetscInt d; 8968 for (d = c - 1; d >= 0; --d) { 8969 if (cone[c] == cone[d]) { 8970 dup = PETSC_TRUE; 8971 break; 8972 } 8973 } 8974 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8975 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8976 for (s = 0; s < supportSize; ++s) { 8977 if (support[s] == p) break; 8978 } 8979 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8980 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8981 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8982 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8983 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8984 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8985 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8986 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]); 8987 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8988 } 8989 } 8990 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8991 if (p != pp) { 8992 storagecheck = PETSC_FALSE; 8993 continue; 8994 } 8995 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8996 PetscCall(DMPlexGetSupport(dm, p, &support)); 8997 for (s = 0; s < supportSize; ++s) { 8998 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8999 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9000 for (c = 0; c < coneSize; ++c) { 9001 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9002 if (cone[c] != pp) { 9003 c = 0; 9004 break; 9005 } 9006 if (cone[c] == p) break; 9007 } 9008 if (c >= coneSize) { 9009 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9010 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9011 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9012 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9013 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9014 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9015 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9016 } 9017 } 9018 } 9019 if (storagecheck) { 9020 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9021 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9022 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9023 } 9024 PetscFunctionReturn(PETSC_SUCCESS); 9025 } 9026 9027 /* 9028 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. 9029 */ 9030 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9031 { 9032 DMPolytopeType cct; 9033 PetscInt ptpoints[4]; 9034 const PetscInt *cone, *ccone, *ptcone; 9035 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9036 9037 PetscFunctionBegin; 9038 *unsplit = 0; 9039 switch (ct) { 9040 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9041 ptpoints[npt++] = c; 9042 break; 9043 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9044 PetscCall(DMPlexGetCone(dm, c, &cone)); 9045 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9046 for (cp = 0; cp < coneSize; ++cp) { 9047 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9048 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9049 } 9050 break; 9051 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9052 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9053 PetscCall(DMPlexGetCone(dm, c, &cone)); 9054 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9055 for (cp = 0; cp < coneSize; ++cp) { 9056 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9057 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9058 for (ccp = 0; ccp < cconeSize; ++ccp) { 9059 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9060 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9061 PetscInt p; 9062 for (p = 0; p < npt; ++p) 9063 if (ptpoints[p] == ccone[ccp]) break; 9064 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9065 } 9066 } 9067 } 9068 break; 9069 default: 9070 break; 9071 } 9072 for (pt = 0; pt < npt; ++pt) { 9073 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9074 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9075 } 9076 PetscFunctionReturn(PETSC_SUCCESS); 9077 } 9078 9079 /*@ 9080 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9081 9082 Input Parameters: 9083 + dm - The `DMPLEX` object 9084 - cellHeight - Normally 0 9085 9086 Level: developer 9087 9088 Notes: 9089 This is a useful diagnostic when creating meshes programmatically. 9090 Currently applicable only to homogeneous simplex or tensor meshes. 9091 9092 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9093 9094 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9095 @*/ 9096 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9097 { 9098 DMPlexInterpolatedFlag interp; 9099 DMPolytopeType ct; 9100 PetscInt vStart, vEnd, cStart, cEnd, c; 9101 9102 PetscFunctionBegin; 9103 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9104 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9105 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9106 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9107 for (c = cStart; c < cEnd; ++c) { 9108 PetscInt *closure = NULL; 9109 PetscInt coneSize, closureSize, cl, Nv = 0; 9110 9111 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9112 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9113 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9114 if (interp == DMPLEX_INTERPOLATED_FULL) { 9115 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9116 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)); 9117 } 9118 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9119 for (cl = 0; cl < closureSize * 2; cl += 2) { 9120 const PetscInt p = closure[cl]; 9121 if ((p >= vStart) && (p < vEnd)) ++Nv; 9122 } 9123 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9124 /* Special Case: Tensor faces with identified vertices */ 9125 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9126 PetscInt unsplit; 9127 9128 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9129 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9130 } 9131 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)); 9132 } 9133 PetscFunctionReturn(PETSC_SUCCESS); 9134 } 9135 9136 /*@ 9137 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9138 9139 Collective 9140 9141 Input Parameters: 9142 + dm - The `DMPLEX` object 9143 - cellHeight - Normally 0 9144 9145 Level: developer 9146 9147 Notes: 9148 This is a useful diagnostic when creating meshes programmatically. 9149 This routine is only relevant for meshes that are fully interpolated across all ranks. 9150 It will error out if a partially interpolated mesh is given on some rank. 9151 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9152 9153 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9154 9155 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9156 @*/ 9157 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9158 { 9159 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9160 DMPlexInterpolatedFlag interpEnum; 9161 9162 PetscFunctionBegin; 9163 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9164 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9165 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9166 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9167 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9168 PetscFunctionReturn(PETSC_SUCCESS); 9169 } 9170 9171 PetscCall(DMGetDimension(dm, &dim)); 9172 PetscCall(DMPlexGetDepth(dm, &depth)); 9173 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9174 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9175 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9176 for (c = cStart; c < cEnd; ++c) { 9177 const PetscInt *cone, *ornt, *faceSizes, *faces; 9178 const DMPolytopeType *faceTypes; 9179 DMPolytopeType ct; 9180 PetscInt numFaces, coneSize, f; 9181 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9182 9183 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9184 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9185 if (unsplit) continue; 9186 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9187 PetscCall(DMPlexGetCone(dm, c, &cone)); 9188 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9189 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9190 for (cl = 0; cl < closureSize * 2; cl += 2) { 9191 const PetscInt p = closure[cl]; 9192 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9193 } 9194 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9195 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); 9196 for (f = 0; f < numFaces; ++f) { 9197 DMPolytopeType fct; 9198 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9199 9200 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9201 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9202 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9203 const PetscInt p = fclosure[cl]; 9204 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9205 } 9206 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]); 9207 for (v = 0; v < fnumCorners; ++v) { 9208 if (fclosure[v] != faces[fOff + v]) { 9209 PetscInt v1; 9210 9211 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9212 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9213 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9214 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9215 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9216 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]); 9217 } 9218 } 9219 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9220 fOff += faceSizes[f]; 9221 } 9222 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9223 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9224 } 9225 } 9226 PetscFunctionReturn(PETSC_SUCCESS); 9227 } 9228 9229 /*@ 9230 DMPlexCheckGeometry - Check the geometry of mesh cells 9231 9232 Input Parameter: 9233 . dm - The `DMPLEX` object 9234 9235 Level: developer 9236 9237 Notes: 9238 This is a useful diagnostic when creating meshes programmatically. 9239 9240 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9241 9242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9243 @*/ 9244 PetscErrorCode DMPlexCheckGeometry(DM dm) 9245 { 9246 Vec coordinates; 9247 PetscReal detJ, J[9], refVol = 1.0; 9248 PetscReal vol; 9249 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9250 9251 PetscFunctionBegin; 9252 PetscCall(DMGetDimension(dm, &dim)); 9253 PetscCall(DMGetCoordinateDim(dm, &dE)); 9254 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9255 PetscCall(DMPlexGetDepth(dm, &depth)); 9256 for (d = 0; d < dim; ++d) refVol *= 2.0; 9257 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9258 /* Make sure local coordinates are created, because that step is collective */ 9259 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9260 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9261 for (c = cStart; c < cEnd; ++c) { 9262 DMPolytopeType ct; 9263 PetscInt unsplit; 9264 PetscBool ignoreZeroVol = PETSC_FALSE; 9265 9266 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9267 switch (ct) { 9268 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9269 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9270 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9271 ignoreZeroVol = PETSC_TRUE; 9272 break; 9273 default: 9274 break; 9275 } 9276 switch (ct) { 9277 case DM_POLYTOPE_TRI_PRISM: 9278 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9279 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9280 case DM_POLYTOPE_PYRAMID: 9281 continue; 9282 default: 9283 break; 9284 } 9285 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9286 if (unsplit) continue; 9287 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9288 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); 9289 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9290 /* This should work with periodicity since DG coordinates should be used */ 9291 if (depth > 1) { 9292 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9293 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); 9294 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9295 } 9296 } 9297 PetscFunctionReturn(PETSC_SUCCESS); 9298 } 9299 9300 /*@ 9301 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9302 9303 Collective 9304 9305 Input Parameters: 9306 + dm - The `DMPLEX` object 9307 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9308 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9309 9310 Level: developer 9311 9312 Notes: 9313 This is mainly intended for debugging/testing purposes. 9314 9315 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9316 9317 Extra roots can come from periodic cuts, where additional points appear on the boundary 9318 9319 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9320 @*/ 9321 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9322 { 9323 PetscInt l, nleaves, nroots, overlap; 9324 const PetscInt *locals; 9325 const PetscSFNode *remotes; 9326 PetscBool distributed; 9327 MPI_Comm comm; 9328 PetscMPIInt rank; 9329 9330 PetscFunctionBegin; 9331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9332 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9333 else pointSF = dm->sf; 9334 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9335 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9336 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9337 { 9338 PetscMPIInt mpiFlag; 9339 9340 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9341 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9342 } 9343 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9344 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9345 if (!distributed) { 9346 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); 9347 PetscFunctionReturn(PETSC_SUCCESS); 9348 } 9349 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); 9350 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9351 9352 /* Check SF graph is compatible with DMPlex chart */ 9353 { 9354 PetscInt pStart, pEnd, maxLeaf; 9355 9356 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9357 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9358 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9359 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9360 } 9361 9362 /* Check Point SF has no local points referenced */ 9363 for (l = 0; l < nleaves; l++) { 9364 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); 9365 } 9366 9367 /* Check there are no cells in interface */ 9368 if (!overlap) { 9369 PetscInt cellHeight, cStart, cEnd; 9370 9371 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9372 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9373 for (l = 0; l < nleaves; ++l) { 9374 const PetscInt point = locals ? locals[l] : l; 9375 9376 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9377 } 9378 } 9379 9380 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9381 { 9382 const PetscInt *rootdegree; 9383 9384 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9385 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9386 for (l = 0; l < nleaves; ++l) { 9387 const PetscInt point = locals ? locals[l] : l; 9388 const PetscInt *cone; 9389 PetscInt coneSize, c, idx; 9390 9391 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9392 PetscCall(DMPlexGetCone(dm, point, &cone)); 9393 for (c = 0; c < coneSize; ++c) { 9394 if (!rootdegree[cone[c]]) { 9395 if (locals) { 9396 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9397 } else { 9398 idx = (cone[c] < nleaves) ? cone[c] : -1; 9399 } 9400 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9401 } 9402 } 9403 } 9404 } 9405 PetscFunctionReturn(PETSC_SUCCESS); 9406 } 9407 9408 /*@ 9409 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9410 9411 Input Parameter: 9412 . dm - The `DMPLEX` object 9413 9414 Level: developer 9415 9416 Notes: 9417 This is a useful diagnostic when creating meshes programmatically. 9418 9419 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9420 9421 Currently does not include `DMPlexCheckCellShape()`. 9422 9423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9424 @*/ 9425 PetscErrorCode DMPlexCheck(DM dm) 9426 { 9427 PetscInt cellHeight; 9428 9429 PetscFunctionBegin; 9430 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9431 PetscCall(DMPlexCheckSymmetry(dm)); 9432 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9433 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9434 PetscCall(DMPlexCheckGeometry(dm)); 9435 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9436 PetscCall(DMPlexCheckInterfaceCones(dm)); 9437 PetscFunctionReturn(PETSC_SUCCESS); 9438 } 9439 9440 typedef struct cell_stats { 9441 PetscReal min, max, sum, squaresum; 9442 PetscInt count; 9443 } cell_stats_t; 9444 9445 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9446 { 9447 PetscInt i, N = *len; 9448 9449 for (i = 0; i < N; i++) { 9450 cell_stats_t *A = (cell_stats_t *)a; 9451 cell_stats_t *B = (cell_stats_t *)b; 9452 9453 B->min = PetscMin(A->min, B->min); 9454 B->max = PetscMax(A->max, B->max); 9455 B->sum += A->sum; 9456 B->squaresum += A->squaresum; 9457 B->count += A->count; 9458 } 9459 } 9460 9461 /*@ 9462 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9463 9464 Collective 9465 9466 Input Parameters: 9467 + dm - The `DMPLEX` object 9468 . output - If true, statistics will be displayed on `stdout` 9469 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9470 9471 Level: developer 9472 9473 Notes: 9474 This is mainly intended for debugging/testing purposes. 9475 9476 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9477 9478 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9479 @*/ 9480 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9481 { 9482 DM dmCoarse; 9483 cell_stats_t stats, globalStats; 9484 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9485 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9486 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9487 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9488 PetscMPIInt rank, size; 9489 9490 PetscFunctionBegin; 9491 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9492 stats.min = PETSC_MAX_REAL; 9493 stats.max = PETSC_MIN_REAL; 9494 stats.sum = stats.squaresum = 0.; 9495 stats.count = 0; 9496 9497 PetscCallMPI(MPI_Comm_size(comm, &size)); 9498 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9499 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9500 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9501 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9502 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9503 for (c = cStart; c < cEnd; c++) { 9504 PetscInt i; 9505 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9506 9507 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9508 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9509 for (i = 0; i < PetscSqr(cdim); ++i) { 9510 frobJ += J[i] * J[i]; 9511 frobInvJ += invJ[i] * invJ[i]; 9512 } 9513 cond2 = frobJ * frobInvJ; 9514 cond = PetscSqrtReal(cond2); 9515 9516 stats.min = PetscMin(stats.min, cond); 9517 stats.max = PetscMax(stats.max, cond); 9518 stats.sum += cond; 9519 stats.squaresum += cond2; 9520 stats.count++; 9521 if (output && cond > limit) { 9522 PetscSection coordSection; 9523 Vec coordsLocal; 9524 PetscScalar *coords = NULL; 9525 PetscInt Nv, d, clSize, cl, *closure = NULL; 9526 9527 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9528 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9529 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9530 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9531 for (i = 0; i < Nv / cdim; ++i) { 9532 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9533 for (d = 0; d < cdim; ++d) { 9534 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9535 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9536 } 9537 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9538 } 9539 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9540 for (cl = 0; cl < clSize * 2; cl += 2) { 9541 const PetscInt edge = closure[cl]; 9542 9543 if ((edge >= eStart) && (edge < eEnd)) { 9544 PetscReal len; 9545 9546 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9547 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9548 } 9549 } 9550 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9551 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9552 } 9553 } 9554 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9555 9556 if (size > 1) { 9557 PetscMPIInt blockLengths[2] = {4, 1}; 9558 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9559 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9560 MPI_Op statReduce; 9561 9562 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9563 PetscCallMPI(MPI_Type_commit(&statType)); 9564 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9565 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9566 PetscCallMPI(MPI_Op_free(&statReduce)); 9567 PetscCallMPI(MPI_Type_free(&statType)); 9568 } else { 9569 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9570 } 9571 if (rank == 0) { 9572 count = globalStats.count; 9573 min = globalStats.min; 9574 max = globalStats.max; 9575 mean = globalStats.sum / globalStats.count; 9576 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9577 } 9578 9579 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)); 9580 PetscCall(PetscFree2(J, invJ)); 9581 9582 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9583 if (dmCoarse) { 9584 PetscBool isplex; 9585 9586 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9587 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9588 } 9589 PetscFunctionReturn(PETSC_SUCCESS); 9590 } 9591 9592 /*@ 9593 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9594 orthogonal quality below given tolerance. 9595 9596 Collective 9597 9598 Input Parameters: 9599 + dm - The `DMPLEX` object 9600 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9601 - atol - [0, 1] Absolute tolerance for tagging cells. 9602 9603 Output Parameters: 9604 + OrthQual - `Vec` containing orthogonal quality per cell 9605 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9606 9607 Options Database Keys: 9608 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9609 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9610 9611 Level: intermediate 9612 9613 Notes: 9614 Orthogonal quality is given by the following formula\: 9615 9616 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9617 9618 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 9619 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9620 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9621 calculating the cosine of the angle between these vectors. 9622 9623 Orthogonal quality ranges from 1 (best) to 0 (worst). 9624 9625 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9626 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9627 9628 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9629 9630 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9631 @*/ 9632 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9633 { 9634 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9635 PetscInt *idx; 9636 PetscScalar *oqVals; 9637 const PetscScalar *cellGeomArr, *faceGeomArr; 9638 PetscReal *ci, *fi, *Ai; 9639 MPI_Comm comm; 9640 Vec cellgeom, facegeom; 9641 DM dmFace, dmCell; 9642 IS glob; 9643 ISLocalToGlobalMapping ltog; 9644 PetscViewer vwr; 9645 9646 PetscFunctionBegin; 9647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9648 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9649 PetscAssertPointer(OrthQual, 4); 9650 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9651 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9652 PetscCall(DMGetDimension(dm, &nc)); 9653 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9654 { 9655 DMPlexInterpolatedFlag interpFlag; 9656 9657 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9658 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9659 PetscMPIInt rank; 9660 9661 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9662 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9663 } 9664 } 9665 if (OrthQualLabel) { 9666 PetscAssertPointer(OrthQualLabel, 5); 9667 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9668 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9669 } else { 9670 *OrthQualLabel = NULL; 9671 } 9672 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9673 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9674 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9675 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9676 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9677 PetscCall(VecCreate(comm, OrthQual)); 9678 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9679 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9680 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9681 PetscCall(VecSetUp(*OrthQual)); 9682 PetscCall(ISDestroy(&glob)); 9683 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9684 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9685 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9686 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9687 PetscCall(VecGetDM(cellgeom, &dmCell)); 9688 PetscCall(VecGetDM(facegeom, &dmFace)); 9689 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9690 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9691 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9692 PetscInt cellarr[2], *adj = NULL; 9693 PetscScalar *cArr, *fArr; 9694 PetscReal minvalc = 1.0, minvalf = 1.0; 9695 PetscFVCellGeom *cg; 9696 9697 idx[cellIter] = cell - cStart; 9698 cellarr[0] = cell; 9699 /* Make indexing into cellGeom easier */ 9700 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9701 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9702 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9703 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9704 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9705 PetscInt i; 9706 const PetscInt neigh = adj[cellneigh]; 9707 PetscReal normci = 0, normfi = 0, normai = 0; 9708 PetscFVCellGeom *cgneigh; 9709 PetscFVFaceGeom *fg; 9710 9711 /* Don't count ourselves in the neighbor list */ 9712 if (neigh == cell) continue; 9713 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9714 cellarr[1] = neigh; 9715 { 9716 PetscInt numcovpts; 9717 const PetscInt *covpts; 9718 9719 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9720 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9721 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9722 } 9723 9724 /* Compute c_i, f_i and their norms */ 9725 for (i = 0; i < nc; i++) { 9726 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9727 fi[i] = fg->centroid[i] - cg->centroid[i]; 9728 Ai[i] = fg->normal[i]; 9729 normci += PetscPowReal(ci[i], 2); 9730 normfi += PetscPowReal(fi[i], 2); 9731 normai += PetscPowReal(Ai[i], 2); 9732 } 9733 normci = PetscSqrtReal(normci); 9734 normfi = PetscSqrtReal(normfi); 9735 normai = PetscSqrtReal(normai); 9736 9737 /* Normalize and compute for each face-cell-normal pair */ 9738 for (i = 0; i < nc; i++) { 9739 ci[i] = ci[i] / normci; 9740 fi[i] = fi[i] / normfi; 9741 Ai[i] = Ai[i] / normai; 9742 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9743 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9744 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9745 } 9746 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9747 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9748 } 9749 PetscCall(PetscFree(adj)); 9750 PetscCall(PetscFree2(cArr, fArr)); 9751 /* Defer to cell if they're equal */ 9752 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9753 if (OrthQualLabel) { 9754 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9755 } 9756 } 9757 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9758 PetscCall(VecAssemblyBegin(*OrthQual)); 9759 PetscCall(VecAssemblyEnd(*OrthQual)); 9760 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9761 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9762 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9763 if (OrthQualLabel) { 9764 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9765 } 9766 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9767 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9768 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9769 PetscFunctionReturn(PETSC_SUCCESS); 9770 } 9771 9772 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9773 * interpolator construction */ 9774 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9775 { 9776 PetscSection section, newSection, gsection; 9777 PetscSF sf; 9778 PetscBool hasConstraints, ghasConstraints; 9779 9780 PetscFunctionBegin; 9781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9782 PetscAssertPointer(odm, 2); 9783 PetscCall(DMGetLocalSection(dm, §ion)); 9784 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9785 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9786 if (!ghasConstraints) { 9787 PetscCall(PetscObjectReference((PetscObject)dm)); 9788 *odm = dm; 9789 PetscFunctionReturn(PETSC_SUCCESS); 9790 } 9791 PetscCall(DMClone(dm, odm)); 9792 PetscCall(DMCopyFields(dm, *odm)); 9793 PetscCall(DMGetLocalSection(*odm, &newSection)); 9794 PetscCall(DMGetPointSF(*odm, &sf)); 9795 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9796 PetscCall(DMSetGlobalSection(*odm, gsection)); 9797 PetscCall(PetscSectionDestroy(&gsection)); 9798 PetscFunctionReturn(PETSC_SUCCESS); 9799 } 9800 9801 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9802 { 9803 DM dmco, dmfo; 9804 Mat interpo; 9805 Vec rscale; 9806 Vec cglobalo, clocal; 9807 Vec fglobal, fglobalo, flocal; 9808 PetscBool regular; 9809 9810 PetscFunctionBegin; 9811 PetscCall(DMGetFullDM(dmc, &dmco)); 9812 PetscCall(DMGetFullDM(dmf, &dmfo)); 9813 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9814 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9815 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9816 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9817 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9818 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9819 PetscCall(VecSet(cglobalo, 0.)); 9820 PetscCall(VecSet(clocal, 0.)); 9821 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9822 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9823 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9824 PetscCall(VecSet(fglobal, 0.)); 9825 PetscCall(VecSet(fglobalo, 0.)); 9826 PetscCall(VecSet(flocal, 0.)); 9827 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9828 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9829 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9830 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9831 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9832 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9833 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9834 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9835 *shift = fglobal; 9836 PetscCall(VecDestroy(&flocal)); 9837 PetscCall(VecDestroy(&fglobalo)); 9838 PetscCall(VecDestroy(&clocal)); 9839 PetscCall(VecDestroy(&cglobalo)); 9840 PetscCall(VecDestroy(&rscale)); 9841 PetscCall(MatDestroy(&interpo)); 9842 PetscCall(DMDestroy(&dmfo)); 9843 PetscCall(DMDestroy(&dmco)); 9844 PetscFunctionReturn(PETSC_SUCCESS); 9845 } 9846 9847 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9848 { 9849 PetscObject shifto; 9850 Vec shift; 9851 9852 PetscFunctionBegin; 9853 if (!interp) { 9854 Vec rscale; 9855 9856 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9857 PetscCall(VecDestroy(&rscale)); 9858 } else { 9859 PetscCall(PetscObjectReference((PetscObject)interp)); 9860 } 9861 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9862 if (!shifto) { 9863 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9864 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9865 shifto = (PetscObject)shift; 9866 PetscCall(VecDestroy(&shift)); 9867 } 9868 shift = (Vec)shifto; 9869 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9870 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9871 PetscCall(MatDestroy(&interp)); 9872 PetscFunctionReturn(PETSC_SUCCESS); 9873 } 9874 9875 /* Pointwise interpolation 9876 Just code FEM for now 9877 u^f = I u^c 9878 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9879 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9880 I_{ij} = psi^f_i phi^c_j 9881 */ 9882 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9883 { 9884 PetscSection gsc, gsf; 9885 PetscInt m, n; 9886 void *ctx; 9887 DM cdm; 9888 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9889 9890 PetscFunctionBegin; 9891 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9892 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9893 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9894 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9895 9896 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9897 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9898 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9899 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9900 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9901 9902 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9903 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9904 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9905 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9906 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9907 if (scaling) { 9908 /* Use naive scaling */ 9909 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9910 } 9911 PetscFunctionReturn(PETSC_SUCCESS); 9912 } 9913 9914 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9915 { 9916 VecScatter ctx; 9917 9918 PetscFunctionBegin; 9919 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9920 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9921 PetscCall(VecScatterDestroy(&ctx)); 9922 PetscFunctionReturn(PETSC_SUCCESS); 9923 } 9924 9925 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[]) 9926 { 9927 const PetscInt Nc = uOff[1] - uOff[0]; 9928 PetscInt c; 9929 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9930 } 9931 9932 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9933 { 9934 DM dmc; 9935 PetscDS ds; 9936 Vec ones, locmass; 9937 IS cellIS; 9938 PetscFormKey key; 9939 PetscInt depth; 9940 9941 PetscFunctionBegin; 9942 PetscCall(DMClone(dm, &dmc)); 9943 PetscCall(DMCopyDisc(dm, dmc)); 9944 PetscCall(DMGetDS(dmc, &ds)); 9945 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9946 PetscCall(DMCreateGlobalVector(dmc, mass)); 9947 PetscCall(DMGetLocalVector(dmc, &ones)); 9948 PetscCall(DMGetLocalVector(dmc, &locmass)); 9949 PetscCall(DMPlexGetDepth(dmc, &depth)); 9950 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9951 PetscCall(VecSet(locmass, 0.0)); 9952 PetscCall(VecSet(ones, 1.0)); 9953 key.label = NULL; 9954 key.value = 0; 9955 key.field = 0; 9956 key.part = 0; 9957 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9958 PetscCall(ISDestroy(&cellIS)); 9959 PetscCall(VecSet(*mass, 0.0)); 9960 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9961 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9962 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9963 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9964 PetscCall(DMDestroy(&dmc)); 9965 PetscFunctionReturn(PETSC_SUCCESS); 9966 } 9967 9968 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9969 { 9970 PetscSection gsc, gsf; 9971 PetscInt m, n; 9972 void *ctx; 9973 DM cdm; 9974 PetscBool regular; 9975 9976 PetscFunctionBegin; 9977 if (dmFine == dmCoarse) { 9978 DM dmc; 9979 PetscDS ds; 9980 PetscWeakForm wf; 9981 Vec u; 9982 IS cellIS; 9983 PetscFormKey key; 9984 PetscInt depth; 9985 9986 PetscCall(DMClone(dmFine, &dmc)); 9987 PetscCall(DMCopyDisc(dmFine, dmc)); 9988 PetscCall(DMGetDS(dmc, &ds)); 9989 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9990 PetscCall(PetscWeakFormClear(wf)); 9991 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9992 PetscCall(DMCreateMatrix(dmc, mass)); 9993 PetscCall(DMGetLocalVector(dmc, &u)); 9994 PetscCall(DMPlexGetDepth(dmc, &depth)); 9995 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9996 PetscCall(MatZeroEntries(*mass)); 9997 key.label = NULL; 9998 key.value = 0; 9999 key.field = 0; 10000 key.part = 0; 10001 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10002 PetscCall(ISDestroy(&cellIS)); 10003 PetscCall(DMRestoreLocalVector(dmc, &u)); 10004 PetscCall(DMDestroy(&dmc)); 10005 } else { 10006 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10007 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10008 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10009 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10010 10011 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10012 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10013 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10014 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10015 10016 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10017 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10018 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10019 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10020 } 10021 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10022 PetscFunctionReturn(PETSC_SUCCESS); 10023 } 10024 10025 /*@ 10026 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10027 10028 Input Parameter: 10029 . dm - The `DMPLEX` object 10030 10031 Output Parameter: 10032 . regular - The flag 10033 10034 Level: intermediate 10035 10036 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10037 @*/ 10038 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10039 { 10040 PetscFunctionBegin; 10041 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10042 PetscAssertPointer(regular, 2); 10043 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10044 PetscFunctionReturn(PETSC_SUCCESS); 10045 } 10046 10047 /*@ 10048 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10049 10050 Input Parameters: 10051 + dm - The `DMPLEX` object 10052 - regular - The flag 10053 10054 Level: intermediate 10055 10056 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10057 @*/ 10058 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10059 { 10060 PetscFunctionBegin; 10061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10062 ((DM_Plex *)dm->data)->regularRefinement = regular; 10063 PetscFunctionReturn(PETSC_SUCCESS); 10064 } 10065 10066 /*@ 10067 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10068 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10069 10070 Not Collective 10071 10072 Input Parameter: 10073 . dm - The `DMPLEX` object 10074 10075 Output Parameters: 10076 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10077 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10078 10079 Level: intermediate 10080 10081 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10082 @*/ 10083 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10084 { 10085 DM_Plex *plex = (DM_Plex *)dm->data; 10086 10087 PetscFunctionBegin; 10088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10089 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10090 if (anchorSection) *anchorSection = plex->anchorSection; 10091 if (anchorIS) *anchorIS = plex->anchorIS; 10092 PetscFunctionReturn(PETSC_SUCCESS); 10093 } 10094 10095 /*@ 10096 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10097 10098 Collective 10099 10100 Input Parameters: 10101 + dm - The `DMPLEX` object 10102 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10103 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10104 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10105 10106 Level: intermediate 10107 10108 Notes: 10109 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10110 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10111 combination of other points' degrees of freedom. 10112 10113 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10114 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10115 10116 The reference counts of `anchorSection` and `anchorIS` are incremented. 10117 10118 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10119 @*/ 10120 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10121 { 10122 DM_Plex *plex = (DM_Plex *)dm->data; 10123 PetscMPIInt result; 10124 10125 PetscFunctionBegin; 10126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10127 if (anchorSection) { 10128 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10129 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10130 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10131 } 10132 if (anchorIS) { 10133 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10134 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10135 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10136 } 10137 10138 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10139 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10140 plex->anchorSection = anchorSection; 10141 10142 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10143 PetscCall(ISDestroy(&plex->anchorIS)); 10144 plex->anchorIS = anchorIS; 10145 10146 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10147 PetscInt size, a, pStart, pEnd; 10148 const PetscInt *anchors; 10149 10150 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10151 PetscCall(ISGetLocalSize(anchorIS, &size)); 10152 PetscCall(ISGetIndices(anchorIS, &anchors)); 10153 for (a = 0; a < size; a++) { 10154 PetscInt p; 10155 10156 p = anchors[a]; 10157 if (p >= pStart && p < pEnd) { 10158 PetscInt dof; 10159 10160 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10161 if (dof) { 10162 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10163 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10164 } 10165 } 10166 } 10167 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10168 } 10169 /* reset the generic constraints */ 10170 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10171 PetscFunctionReturn(PETSC_SUCCESS); 10172 } 10173 10174 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10175 { 10176 PetscSection anchorSection; 10177 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10178 10179 PetscFunctionBegin; 10180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10181 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10182 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10183 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10184 if (numFields) { 10185 PetscInt f; 10186 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10187 10188 for (f = 0; f < numFields; f++) { 10189 PetscInt numComp; 10190 10191 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10192 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10193 } 10194 } 10195 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10196 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10197 pStart = PetscMax(pStart, sStart); 10198 pEnd = PetscMin(pEnd, sEnd); 10199 pEnd = PetscMax(pStart, pEnd); 10200 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10201 for (p = pStart; p < pEnd; p++) { 10202 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10203 if (dof) { 10204 PetscCall(PetscSectionGetDof(section, p, &dof)); 10205 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10206 for (f = 0; f < numFields; f++) { 10207 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10208 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10209 } 10210 } 10211 } 10212 PetscCall(PetscSectionSetUp(*cSec)); 10213 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10214 PetscFunctionReturn(PETSC_SUCCESS); 10215 } 10216 10217 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10218 { 10219 PetscSection aSec; 10220 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10221 const PetscInt *anchors; 10222 PetscInt numFields, f; 10223 IS aIS; 10224 MatType mtype; 10225 PetscBool iscuda, iskokkos; 10226 10227 PetscFunctionBegin; 10228 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10229 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10230 PetscCall(PetscSectionGetStorageSize(section, &n)); 10231 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10232 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10233 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10234 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10235 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10236 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10237 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10238 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10239 else mtype = MATSEQAIJ; 10240 PetscCall(MatSetType(*cMat, mtype)); 10241 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10242 PetscCall(ISGetIndices(aIS, &anchors)); 10243 /* cSec will be a subset of aSec and section */ 10244 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10245 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10246 PetscCall(PetscMalloc1(m + 1, &i)); 10247 i[0] = 0; 10248 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10249 for (p = pStart; p < pEnd; p++) { 10250 PetscInt rDof, rOff, r; 10251 10252 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10253 if (!rDof) continue; 10254 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10255 if (numFields) { 10256 for (f = 0; f < numFields; f++) { 10257 annz = 0; 10258 for (r = 0; r < rDof; r++) { 10259 a = anchors[rOff + r]; 10260 if (a < sStart || a >= sEnd) continue; 10261 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10262 annz += aDof; 10263 } 10264 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10265 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10266 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10267 } 10268 } else { 10269 annz = 0; 10270 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10271 for (q = 0; q < dof; q++) { 10272 a = anchors[rOff + q]; 10273 if (a < sStart || a >= sEnd) continue; 10274 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10275 annz += aDof; 10276 } 10277 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10278 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10279 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10280 } 10281 } 10282 nnz = i[m]; 10283 PetscCall(PetscMalloc1(nnz, &j)); 10284 offset = 0; 10285 for (p = pStart; p < pEnd; p++) { 10286 if (numFields) { 10287 for (f = 0; f < numFields; f++) { 10288 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10289 for (q = 0; q < dof; q++) { 10290 PetscInt rDof, rOff, r; 10291 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10292 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10293 for (r = 0; r < rDof; r++) { 10294 PetscInt s; 10295 10296 a = anchors[rOff + r]; 10297 if (a < sStart || a >= sEnd) continue; 10298 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10299 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10300 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10301 } 10302 } 10303 } 10304 } else { 10305 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10306 for (q = 0; q < dof; q++) { 10307 PetscInt rDof, rOff, r; 10308 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10309 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10310 for (r = 0; r < rDof; r++) { 10311 PetscInt s; 10312 10313 a = anchors[rOff + r]; 10314 if (a < sStart || a >= sEnd) continue; 10315 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10316 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10317 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10318 } 10319 } 10320 } 10321 } 10322 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10323 PetscCall(PetscFree(i)); 10324 PetscCall(PetscFree(j)); 10325 PetscCall(ISRestoreIndices(aIS, &anchors)); 10326 PetscFunctionReturn(PETSC_SUCCESS); 10327 } 10328 10329 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10330 { 10331 DM_Plex *plex = (DM_Plex *)dm->data; 10332 PetscSection anchorSection, section, cSec; 10333 Mat cMat; 10334 10335 PetscFunctionBegin; 10336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10337 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10338 if (anchorSection) { 10339 PetscInt Nf; 10340 10341 PetscCall(DMGetLocalSection(dm, §ion)); 10342 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10343 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10344 PetscCall(DMGetNumFields(dm, &Nf)); 10345 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10346 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10347 PetscCall(PetscSectionDestroy(&cSec)); 10348 PetscCall(MatDestroy(&cMat)); 10349 } 10350 PetscFunctionReturn(PETSC_SUCCESS); 10351 } 10352 10353 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10354 { 10355 IS subis; 10356 PetscSection section, subsection; 10357 10358 PetscFunctionBegin; 10359 PetscCall(DMGetLocalSection(dm, §ion)); 10360 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10361 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10362 /* Create subdomain */ 10363 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10364 /* Create submodel */ 10365 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10366 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10367 PetscCall(DMSetLocalSection(*subdm, subsection)); 10368 PetscCall(PetscSectionDestroy(&subsection)); 10369 PetscCall(DMCopyDisc(dm, *subdm)); 10370 /* Create map from submodel to global model */ 10371 if (is) { 10372 PetscSection sectionGlobal, subsectionGlobal; 10373 IS spIS; 10374 const PetscInt *spmap; 10375 PetscInt *subIndices; 10376 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10377 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10378 10379 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10380 PetscCall(ISGetIndices(spIS, &spmap)); 10381 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10382 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10383 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10384 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10385 for (p = pStart; p < pEnd; ++p) { 10386 PetscInt gdof, pSubSize = 0; 10387 10388 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10389 if (gdof > 0) { 10390 for (f = 0; f < Nf; ++f) { 10391 PetscInt fdof, fcdof; 10392 10393 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10394 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10395 pSubSize += fdof - fcdof; 10396 } 10397 subSize += pSubSize; 10398 if (pSubSize) { 10399 if (bs < 0) { 10400 bs = pSubSize; 10401 } else if (bs != pSubSize) { 10402 /* Layout does not admit a pointwise block size */ 10403 bs = 1; 10404 } 10405 } 10406 } 10407 } 10408 /* Must have same blocksize on all procs (some might have no points) */ 10409 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10410 bsLocal[1] = bs; 10411 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10412 if (bsMinMax[0] != bsMinMax[1]) { 10413 bs = 1; 10414 } else { 10415 bs = bsMinMax[0]; 10416 } 10417 PetscCall(PetscMalloc1(subSize, &subIndices)); 10418 for (p = pStart; p < pEnd; ++p) { 10419 PetscInt gdof, goff; 10420 10421 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10422 if (gdof > 0) { 10423 const PetscInt point = spmap[p]; 10424 10425 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10426 for (f = 0; f < Nf; ++f) { 10427 PetscInt fdof, fcdof, fc, f2, poff = 0; 10428 10429 /* Can get rid of this loop by storing field information in the global section */ 10430 for (f2 = 0; f2 < f; ++f2) { 10431 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10432 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10433 poff += fdof - fcdof; 10434 } 10435 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10436 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10437 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10438 } 10439 } 10440 } 10441 PetscCall(ISRestoreIndices(spIS, &spmap)); 10442 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10443 if (bs > 1) { 10444 /* We need to check that the block size does not come from non-contiguous fields */ 10445 PetscInt i, j, set = 1; 10446 for (i = 0; i < subSize; i += bs) { 10447 for (j = 0; j < bs; ++j) { 10448 if (subIndices[i + j] != subIndices[i] + j) { 10449 set = 0; 10450 break; 10451 } 10452 } 10453 } 10454 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10455 } 10456 /* Attach nullspace */ 10457 for (f = 0; f < Nf; ++f) { 10458 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10459 if ((*subdm)->nullspaceConstructors[f]) break; 10460 } 10461 if (f < Nf) { 10462 MatNullSpace nullSpace; 10463 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10464 10465 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10466 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10467 } 10468 } 10469 PetscFunctionReturn(PETSC_SUCCESS); 10470 } 10471 10472 /*@ 10473 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10474 10475 Input Parameters: 10476 + dm - The `DM` 10477 - dummy - unused argument 10478 10479 Options Database Key: 10480 . -dm_plex_monitor_throughput - Activate the monitor 10481 10482 Level: developer 10483 10484 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10485 @*/ 10486 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10487 { 10488 PetscLogHandler default_handler; 10489 10490 PetscFunctionBegin; 10491 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10492 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10493 if (default_handler) { 10494 PetscLogEvent event; 10495 PetscEventPerfInfo eventInfo; 10496 PetscReal cellRate, flopRate; 10497 PetscInt cStart, cEnd, Nf, N; 10498 const char *name; 10499 10500 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10501 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10502 PetscCall(DMGetNumFields(dm, &Nf)); 10503 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10504 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10505 N = (cEnd - cStart) * Nf * eventInfo.count; 10506 flopRate = eventInfo.flops / eventInfo.time; 10507 cellRate = N / eventInfo.time; 10508 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))); 10509 } else { 10510 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."); 10511 } 10512 PetscFunctionReturn(PETSC_SUCCESS); 10513 } 10514