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 if (mesh->periodic.periodic_points) { 2740 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2741 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2742 } 2743 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2744 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2745 PetscCall(ISDestroy(&mesh->anchorIS)); 2746 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2747 PetscCall(PetscFree(mesh->parents)); 2748 PetscCall(PetscFree(mesh->childIDs)); 2749 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2750 PetscCall(PetscFree(mesh->children)); 2751 PetscCall(DMDestroy(&mesh->referenceTree)); 2752 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2753 PetscCall(PetscFree(mesh->neighbors)); 2754 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2755 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2756 PetscCall(PetscFree(mesh)); 2757 PetscFunctionReturn(PETSC_SUCCESS); 2758 } 2759 2760 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2761 { 2762 PetscSection sectionGlobal, sectionLocal; 2763 PetscInt bs = -1, mbs; 2764 PetscInt localSize, localStart = 0; 2765 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2766 MatType mtype; 2767 ISLocalToGlobalMapping ltog; 2768 2769 PetscFunctionBegin; 2770 PetscCall(MatInitializePackage()); 2771 mtype = dm->mattype; 2772 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2773 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2774 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2775 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2776 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2777 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2778 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2779 PetscCall(MatSetType(*J, mtype)); 2780 PetscCall(MatSetFromOptions(*J)); 2781 PetscCall(MatGetBlockSize(*J, &mbs)); 2782 if (mbs > 1) bs = mbs; 2783 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2784 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2785 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2786 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2787 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2788 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2789 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2790 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2791 if (!isShell) { 2792 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2793 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2794 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2795 2796 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2797 2798 PetscCall(PetscCalloc1(localSize, &pblocks)); 2799 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2800 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2801 for (p = pStart; p < pEnd; ++p) { 2802 switch (dm->blocking_type) { 2803 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2804 PetscInt bdof, offset; 2805 2806 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2807 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2808 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2809 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2810 // Signal block concatenation 2811 if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof); 2812 dof = dof < 0 ? -(dof + 1) : dof; 2813 bdof = cdof && (dof - cdof) ? 1 : dof; 2814 if (dof) { 2815 if (bs < 0) { 2816 bs = bdof; 2817 } else if (bs != bdof) { 2818 bs = 1; 2819 } 2820 } 2821 } break; 2822 case DM_BLOCKING_FIELD_NODE: { 2823 for (PetscInt field = 0; field < num_fields; field++) { 2824 PetscInt num_comp, bdof, offset; 2825 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2826 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2827 if (dof < 0) continue; 2828 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2829 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2830 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); 2831 PetscInt num_nodes = dof / num_comp; 2832 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2833 // Handle possibly constant block size (unlikely) 2834 bdof = cdof && (dof - cdof) ? 1 : dof; 2835 if (dof) { 2836 if (bs < 0) { 2837 bs = bdof; 2838 } else if (bs != bdof) { 2839 bs = 1; 2840 } 2841 } 2842 } 2843 } break; 2844 } 2845 } 2846 /* Must have same blocksize on all procs (some might have no points) */ 2847 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2848 bsLocal[1] = bs; 2849 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2850 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2851 else bs = bsMinMax[0]; 2852 bs = PetscMax(1, bs); 2853 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2854 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2855 PetscCall(MatSetBlockSize(*J, bs)); 2856 PetscCall(MatSetUp(*J)); 2857 } else { 2858 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2859 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2860 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2861 } 2862 { // Consolidate blocks 2863 PetscInt nblocks = 0; 2864 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2865 if (pblocks[i] == 0) continue; 2866 // Negative block size indicates the blocks should be concatenated 2867 if (pblocks[i] < 0) { 2868 pblocks[i] = -pblocks[i]; 2869 pblocks[nblocks - 1] += pblocks[i]; 2870 } else { 2871 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2872 } 2873 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]); 2874 } 2875 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2876 } 2877 PetscCall(PetscFree(pblocks)); 2878 } 2879 PetscCall(MatSetDM(*J, dm)); 2880 PetscFunctionReturn(PETSC_SUCCESS); 2881 } 2882 2883 /*@ 2884 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2885 2886 Not Collective 2887 2888 Input Parameter: 2889 . dm - The `DMPLEX` 2890 2891 Output Parameter: 2892 . subsection - The subdomain section 2893 2894 Level: developer 2895 2896 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2897 @*/ 2898 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2899 { 2900 DM_Plex *mesh = (DM_Plex *)dm->data; 2901 2902 PetscFunctionBegin; 2903 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2904 if (!mesh->subdomainSection) { 2905 PetscSection section; 2906 PetscSF sf; 2907 2908 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2909 PetscCall(DMGetLocalSection(dm, §ion)); 2910 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2911 PetscCall(PetscSFDestroy(&sf)); 2912 } 2913 *subsection = mesh->subdomainSection; 2914 PetscFunctionReturn(PETSC_SUCCESS); 2915 } 2916 2917 /*@ 2918 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2919 2920 Not Collective 2921 2922 Input Parameter: 2923 . dm - The `DMPLEX` 2924 2925 Output Parameters: 2926 + pStart - The first mesh point 2927 - pEnd - The upper bound for mesh points 2928 2929 Level: beginner 2930 2931 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2932 @*/ 2933 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2934 { 2935 DM_Plex *mesh = (DM_Plex *)dm->data; 2936 2937 PetscFunctionBegin; 2938 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2939 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2940 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2941 PetscFunctionReturn(PETSC_SUCCESS); 2942 } 2943 2944 /*@ 2945 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2946 2947 Not Collective 2948 2949 Input Parameters: 2950 + dm - The `DMPLEX` 2951 . pStart - The first mesh point 2952 - pEnd - The upper bound for mesh points 2953 2954 Level: beginner 2955 2956 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2957 @*/ 2958 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2959 { 2960 DM_Plex *mesh = (DM_Plex *)dm->data; 2961 2962 PetscFunctionBegin; 2963 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2964 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2965 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2966 PetscCall(PetscFree(mesh->cellTypes)); 2967 PetscFunctionReturn(PETSC_SUCCESS); 2968 } 2969 2970 /*@ 2971 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2972 2973 Not Collective 2974 2975 Input Parameters: 2976 + dm - The `DMPLEX` 2977 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2978 2979 Output Parameter: 2980 . size - The cone size for point `p` 2981 2982 Level: beginner 2983 2984 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2985 @*/ 2986 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2987 { 2988 DM_Plex *mesh = (DM_Plex *)dm->data; 2989 2990 PetscFunctionBegin; 2991 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2992 PetscAssertPointer(size, 3); 2993 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2994 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2995 PetscFunctionReturn(PETSC_SUCCESS); 2996 } 2997 2998 /*@ 2999 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3000 3001 Not Collective 3002 3003 Input Parameters: 3004 + dm - The `DMPLEX` 3005 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3006 - size - The cone size for point `p` 3007 3008 Level: beginner 3009 3010 Note: 3011 This should be called after `DMPlexSetChart()`. 3012 3013 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3014 @*/ 3015 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3016 { 3017 DM_Plex *mesh = (DM_Plex *)dm->data; 3018 3019 PetscFunctionBegin; 3020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3021 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3022 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3023 PetscFunctionReturn(PETSC_SUCCESS); 3024 } 3025 3026 /*@C 3027 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3028 3029 Not Collective 3030 3031 Input Parameters: 3032 + dm - The `DMPLEX` 3033 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3034 3035 Output Parameter: 3036 . cone - An array of points which are on the in-edges for point `p` 3037 3038 Level: beginner 3039 3040 Fortran Notes: 3041 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3042 `DMPlexRestoreCone()` is not needed/available in C. 3043 3044 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3045 @*/ 3046 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3047 { 3048 DM_Plex *mesh = (DM_Plex *)dm->data; 3049 PetscInt off; 3050 3051 PetscFunctionBegin; 3052 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3053 PetscAssertPointer(cone, 3); 3054 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3055 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3056 PetscFunctionReturn(PETSC_SUCCESS); 3057 } 3058 3059 /*@C 3060 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3061 3062 Not Collective 3063 3064 Input Parameters: 3065 + dm - The `DMPLEX` 3066 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3067 3068 Output Parameters: 3069 + pConesSection - `PetscSection` describing the layout of `pCones` 3070 - pCones - An array of points which are on the in-edges for the point set `p` 3071 3072 Level: intermediate 3073 3074 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3075 @*/ 3076 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3077 { 3078 PetscSection cs, newcs; 3079 PetscInt *cones; 3080 PetscInt *newarr = NULL; 3081 PetscInt n; 3082 3083 PetscFunctionBegin; 3084 PetscCall(DMPlexGetCones(dm, &cones)); 3085 PetscCall(DMPlexGetConeSection(dm, &cs)); 3086 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3087 if (pConesSection) *pConesSection = newcs; 3088 if (pCones) { 3089 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3090 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3091 } 3092 PetscFunctionReturn(PETSC_SUCCESS); 3093 } 3094 3095 /*@ 3096 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3097 3098 Not Collective 3099 3100 Input Parameters: 3101 + dm - The `DMPLEX` 3102 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3103 3104 Output Parameter: 3105 . expandedPoints - An array of vertices recursively expanded from input points 3106 3107 Level: advanced 3108 3109 Notes: 3110 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3111 3112 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3113 3114 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3115 `DMPlexGetDepth()`, `IS` 3116 @*/ 3117 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3118 { 3119 IS *expandedPointsAll; 3120 PetscInt depth; 3121 3122 PetscFunctionBegin; 3123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3124 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3125 PetscAssertPointer(expandedPoints, 3); 3126 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3127 *expandedPoints = expandedPointsAll[0]; 3128 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3129 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3130 PetscFunctionReturn(PETSC_SUCCESS); 3131 } 3132 3133 /*@ 3134 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). 3135 3136 Not Collective 3137 3138 Input Parameters: 3139 + dm - The `DMPLEX` 3140 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3141 3142 Output Parameters: 3143 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3144 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3145 - sections - (optional) An array of sections which describe mappings from points to their cone points 3146 3147 Level: advanced 3148 3149 Notes: 3150 Like `DMPlexGetConeTuple()` but recursive. 3151 3152 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. 3153 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3154 3155 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\: 3156 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3157 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3158 3159 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3160 `DMPlexGetDepth()`, `PetscSection`, `IS` 3161 @*/ 3162 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3163 { 3164 const PetscInt *arr0 = NULL, *cone = NULL; 3165 PetscInt *arr = NULL, *newarr = NULL; 3166 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3167 IS *expandedPoints_; 3168 PetscSection *sections_; 3169 3170 PetscFunctionBegin; 3171 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3172 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3173 if (depth) PetscAssertPointer(depth, 3); 3174 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3175 if (sections) PetscAssertPointer(sections, 5); 3176 PetscCall(ISGetLocalSize(points, &n)); 3177 PetscCall(ISGetIndices(points, &arr0)); 3178 PetscCall(DMPlexGetDepth(dm, &depth_)); 3179 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3180 PetscCall(PetscCalloc1(depth_, §ions_)); 3181 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3182 for (d = depth_ - 1; d >= 0; d--) { 3183 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3184 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3185 for (i = 0; i < n; i++) { 3186 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3187 if (arr[i] >= start && arr[i] < end) { 3188 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3189 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3190 } else { 3191 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3192 } 3193 } 3194 PetscCall(PetscSectionSetUp(sections_[d])); 3195 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3196 PetscCall(PetscMalloc1(newn, &newarr)); 3197 for (i = 0; i < n; i++) { 3198 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3199 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3200 if (cn > 1) { 3201 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3202 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3203 } else { 3204 newarr[co] = arr[i]; 3205 } 3206 } 3207 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3208 arr = newarr; 3209 n = newn; 3210 } 3211 PetscCall(ISRestoreIndices(points, &arr0)); 3212 *depth = depth_; 3213 if (expandedPoints) *expandedPoints = expandedPoints_; 3214 else { 3215 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3216 PetscCall(PetscFree(expandedPoints_)); 3217 } 3218 if (sections) *sections = sections_; 3219 else { 3220 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3221 PetscCall(PetscFree(sections_)); 3222 } 3223 PetscFunctionReturn(PETSC_SUCCESS); 3224 } 3225 3226 /*@ 3227 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3228 3229 Not Collective 3230 3231 Input Parameters: 3232 + dm - The `DMPLEX` 3233 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3234 3235 Output Parameters: 3236 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3237 . expandedPoints - (optional) An array of recursively expanded cones 3238 - sections - (optional) An array of sections which describe mappings from points to their cone points 3239 3240 Level: advanced 3241 3242 Note: 3243 See `DMPlexGetConeRecursive()` 3244 3245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3246 `DMPlexGetDepth()`, `IS`, `PetscSection` 3247 @*/ 3248 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3249 { 3250 PetscInt d, depth_; 3251 3252 PetscFunctionBegin; 3253 PetscCall(DMPlexGetDepth(dm, &depth_)); 3254 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3255 if (depth) *depth = 0; 3256 if (expandedPoints) { 3257 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3258 PetscCall(PetscFree(*expandedPoints)); 3259 } 3260 if (sections) { 3261 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3262 PetscCall(PetscFree(*sections)); 3263 } 3264 PetscFunctionReturn(PETSC_SUCCESS); 3265 } 3266 3267 /*@ 3268 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 3269 3270 Not Collective 3271 3272 Input Parameters: 3273 + dm - The `DMPLEX` 3274 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3275 - cone - An array of points which are on the in-edges for point `p` 3276 3277 Level: beginner 3278 3279 Note: 3280 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3281 3282 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3283 @*/ 3284 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3285 { 3286 DM_Plex *mesh = (DM_Plex *)dm->data; 3287 PetscInt dof, off, c; 3288 3289 PetscFunctionBegin; 3290 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3291 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3292 if (dof) PetscAssertPointer(cone, 3); 3293 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3294 if (PetscDefined(USE_DEBUG)) { 3295 PetscInt pStart, pEnd; 3296 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3297 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); 3298 for (c = 0; c < dof; ++c) { 3299 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); 3300 mesh->cones[off + c] = cone[c]; 3301 } 3302 } else { 3303 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3304 } 3305 PetscFunctionReturn(PETSC_SUCCESS); 3306 } 3307 3308 /*@C 3309 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3310 3311 Not Collective 3312 3313 Input Parameters: 3314 + dm - The `DMPLEX` 3315 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3316 3317 Output Parameter: 3318 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3319 integer giving the prescription for cone traversal. 3320 3321 Level: beginner 3322 3323 Note: 3324 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3325 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3326 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3327 with the identity. 3328 3329 Fortran Notes: 3330 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3331 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3332 3333 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3334 @*/ 3335 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3336 { 3337 DM_Plex *mesh = (DM_Plex *)dm->data; 3338 PetscInt off; 3339 3340 PetscFunctionBegin; 3341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3342 if (PetscDefined(USE_DEBUG)) { 3343 PetscInt dof; 3344 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3345 if (dof) PetscAssertPointer(coneOrientation, 3); 3346 } 3347 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3348 3349 *coneOrientation = &mesh->coneOrientations[off]; 3350 PetscFunctionReturn(PETSC_SUCCESS); 3351 } 3352 3353 /*@ 3354 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3355 3356 Not Collective 3357 3358 Input Parameters: 3359 + dm - The `DMPLEX` 3360 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3361 - coneOrientation - An array of orientations 3362 3363 Level: beginner 3364 3365 Notes: 3366 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3367 3368 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3369 3370 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3371 @*/ 3372 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3373 { 3374 DM_Plex *mesh = (DM_Plex *)dm->data; 3375 PetscInt pStart, pEnd; 3376 PetscInt dof, off, c; 3377 3378 PetscFunctionBegin; 3379 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3380 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3381 if (dof) PetscAssertPointer(coneOrientation, 3); 3382 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3383 if (PetscDefined(USE_DEBUG)) { 3384 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3385 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); 3386 for (c = 0; c < dof; ++c) { 3387 PetscInt cdof, o = coneOrientation[c]; 3388 3389 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3390 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); 3391 mesh->coneOrientations[off + c] = o; 3392 } 3393 } else { 3394 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3395 } 3396 PetscFunctionReturn(PETSC_SUCCESS); 3397 } 3398 3399 /*@ 3400 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3401 3402 Not Collective 3403 3404 Input Parameters: 3405 + dm - The `DMPLEX` 3406 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3407 . conePos - The local index in the cone where the point should be put 3408 - conePoint - The mesh point to insert 3409 3410 Level: beginner 3411 3412 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3413 @*/ 3414 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3415 { 3416 DM_Plex *mesh = (DM_Plex *)dm->data; 3417 PetscInt pStart, pEnd; 3418 PetscInt dof, off; 3419 3420 PetscFunctionBegin; 3421 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3422 if (PetscDefined(USE_DEBUG)) { 3423 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3424 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); 3425 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); 3426 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3427 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); 3428 } 3429 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3430 mesh->cones[off + conePos] = conePoint; 3431 PetscFunctionReturn(PETSC_SUCCESS); 3432 } 3433 3434 /*@ 3435 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3436 3437 Not Collective 3438 3439 Input Parameters: 3440 + dm - The `DMPLEX` 3441 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3442 . conePos - The local index in the cone where the point should be put 3443 - coneOrientation - The point orientation to insert 3444 3445 Level: beginner 3446 3447 Note: 3448 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3449 3450 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3451 @*/ 3452 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3453 { 3454 DM_Plex *mesh = (DM_Plex *)dm->data; 3455 PetscInt pStart, pEnd; 3456 PetscInt dof, off; 3457 3458 PetscFunctionBegin; 3459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3460 if (PetscDefined(USE_DEBUG)) { 3461 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3462 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); 3463 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3464 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); 3465 } 3466 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3467 mesh->coneOrientations[off + conePos] = coneOrientation; 3468 PetscFunctionReturn(PETSC_SUCCESS); 3469 } 3470 3471 /*@C 3472 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3473 3474 Not collective 3475 3476 Input Parameters: 3477 + dm - The DMPlex 3478 - p - The point, which must lie in the chart set with DMPlexSetChart() 3479 3480 Output Parameters: 3481 + cone - An array of points which are on the in-edges for point `p` 3482 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3483 integer giving the prescription for cone traversal. 3484 3485 Level: beginner 3486 3487 Notes: 3488 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3489 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3490 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3491 with the identity. 3492 3493 Fortran Notes: 3494 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3495 `DMPlexRestoreCone()` is not needed/available in C. 3496 3497 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3498 @*/ 3499 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3500 { 3501 DM_Plex *mesh = (DM_Plex *)dm->data; 3502 3503 PetscFunctionBegin; 3504 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3505 if (mesh->tr) { 3506 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3507 } else { 3508 PetscInt off; 3509 if (PetscDefined(USE_DEBUG)) { 3510 PetscInt dof; 3511 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3512 if (dof) { 3513 if (cone) PetscAssertPointer(cone, 3); 3514 if (ornt) PetscAssertPointer(ornt, 4); 3515 } 3516 } 3517 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3518 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3519 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3520 } 3521 PetscFunctionReturn(PETSC_SUCCESS); 3522 } 3523 3524 /*@C 3525 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3526 3527 Not Collective 3528 3529 Input Parameters: 3530 + dm - The DMPlex 3531 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3532 . cone - An array of points which are on the in-edges for point p 3533 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3534 integer giving the prescription for cone traversal. 3535 3536 Level: beginner 3537 3538 Notes: 3539 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3540 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3541 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3542 with the identity. 3543 3544 Fortran Notes: 3545 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3546 `DMPlexRestoreCone()` is not needed/available in C. 3547 3548 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3549 @*/ 3550 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3551 { 3552 DM_Plex *mesh = (DM_Plex *)dm->data; 3553 3554 PetscFunctionBegin; 3555 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3556 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3557 PetscFunctionReturn(PETSC_SUCCESS); 3558 } 3559 3560 /*@ 3561 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3562 3563 Not Collective 3564 3565 Input Parameters: 3566 + dm - The `DMPLEX` 3567 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3568 3569 Output Parameter: 3570 . size - The support size for point `p` 3571 3572 Level: beginner 3573 3574 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3575 @*/ 3576 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3577 { 3578 DM_Plex *mesh = (DM_Plex *)dm->data; 3579 3580 PetscFunctionBegin; 3581 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3582 PetscAssertPointer(size, 3); 3583 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3584 PetscFunctionReturn(PETSC_SUCCESS); 3585 } 3586 3587 /*@ 3588 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3589 3590 Not Collective 3591 3592 Input Parameters: 3593 + dm - The `DMPLEX` 3594 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3595 - size - The support size for point `p` 3596 3597 Level: beginner 3598 3599 Note: 3600 This should be called after `DMPlexSetChart()`. 3601 3602 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3603 @*/ 3604 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3605 { 3606 DM_Plex *mesh = (DM_Plex *)dm->data; 3607 3608 PetscFunctionBegin; 3609 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3610 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3611 PetscFunctionReturn(PETSC_SUCCESS); 3612 } 3613 3614 /*@C 3615 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3616 3617 Not Collective 3618 3619 Input Parameters: 3620 + dm - The `DMPLEX` 3621 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3622 3623 Output Parameter: 3624 . support - An array of points which are on the out-edges for point `p` 3625 3626 Level: beginner 3627 3628 Fortran Notes: 3629 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3630 `DMPlexRestoreSupport()` is not needed/available in C. 3631 3632 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3633 @*/ 3634 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3635 { 3636 DM_Plex *mesh = (DM_Plex *)dm->data; 3637 PetscInt off; 3638 3639 PetscFunctionBegin; 3640 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3641 PetscAssertPointer(support, 3); 3642 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3643 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3644 PetscFunctionReturn(PETSC_SUCCESS); 3645 } 3646 3647 /*@ 3648 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3649 3650 Not Collective 3651 3652 Input Parameters: 3653 + dm - The `DMPLEX` 3654 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3655 - support - An array of points which are on the out-edges for point `p` 3656 3657 Level: beginner 3658 3659 Note: 3660 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3661 3662 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3663 @*/ 3664 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3665 { 3666 DM_Plex *mesh = (DM_Plex *)dm->data; 3667 PetscInt pStart, pEnd; 3668 PetscInt dof, off, c; 3669 3670 PetscFunctionBegin; 3671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3672 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3673 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3674 if (dof) PetscAssertPointer(support, 3); 3675 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3676 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); 3677 for (c = 0; c < dof; ++c) { 3678 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); 3679 mesh->supports[off + c] = support[c]; 3680 } 3681 PetscFunctionReturn(PETSC_SUCCESS); 3682 } 3683 3684 /*@ 3685 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3686 3687 Not Collective 3688 3689 Input Parameters: 3690 + dm - The `DMPLEX` 3691 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3692 . supportPos - The local index in the cone where the point should be put 3693 - supportPoint - The mesh point to insert 3694 3695 Level: beginner 3696 3697 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3698 @*/ 3699 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3700 { 3701 DM_Plex *mesh = (DM_Plex *)dm->data; 3702 PetscInt pStart, pEnd; 3703 PetscInt dof, off; 3704 3705 PetscFunctionBegin; 3706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3707 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3708 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3709 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3710 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); 3711 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); 3712 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); 3713 mesh->supports[off + supportPos] = supportPoint; 3714 PetscFunctionReturn(PETSC_SUCCESS); 3715 } 3716 3717 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3718 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3719 { 3720 switch (ct) { 3721 case DM_POLYTOPE_SEGMENT: 3722 if (o == -1) return -2; 3723 break; 3724 case DM_POLYTOPE_TRIANGLE: 3725 if (o == -3) return -1; 3726 if (o == -2) return -3; 3727 if (o == -1) return -2; 3728 break; 3729 case DM_POLYTOPE_QUADRILATERAL: 3730 if (o == -4) return -2; 3731 if (o == -3) return -1; 3732 if (o == -2) return -4; 3733 if (o == -1) return -3; 3734 break; 3735 default: 3736 return o; 3737 } 3738 return o; 3739 } 3740 3741 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3742 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3743 { 3744 switch (ct) { 3745 case DM_POLYTOPE_SEGMENT: 3746 if ((o == -2) || (o == 1)) return -1; 3747 if (o == -1) return 0; 3748 break; 3749 case DM_POLYTOPE_TRIANGLE: 3750 if (o == -3) return -2; 3751 if (o == -2) return -1; 3752 if (o == -1) return -3; 3753 break; 3754 case DM_POLYTOPE_QUADRILATERAL: 3755 if (o == -4) return -2; 3756 if (o == -3) return -1; 3757 if (o == -2) return -4; 3758 if (o == -1) return -3; 3759 break; 3760 default: 3761 return o; 3762 } 3763 return o; 3764 } 3765 3766 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3767 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3768 { 3769 PetscInt pStart, pEnd, p; 3770 3771 PetscFunctionBegin; 3772 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3773 for (p = pStart; p < pEnd; ++p) { 3774 const PetscInt *cone, *ornt; 3775 PetscInt coneSize, c; 3776 3777 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3778 PetscCall(DMPlexGetCone(dm, p, &cone)); 3779 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3780 for (c = 0; c < coneSize; ++c) { 3781 DMPolytopeType ct; 3782 const PetscInt o = ornt[c]; 3783 3784 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3785 switch (ct) { 3786 case DM_POLYTOPE_SEGMENT: 3787 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3788 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3789 break; 3790 case DM_POLYTOPE_TRIANGLE: 3791 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3792 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3793 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3794 break; 3795 case DM_POLYTOPE_QUADRILATERAL: 3796 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3797 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3798 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3799 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3800 break; 3801 default: 3802 break; 3803 } 3804 } 3805 } 3806 PetscFunctionReturn(PETSC_SUCCESS); 3807 } 3808 3809 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3810 { 3811 DM_Plex *mesh = (DM_Plex *)dm->data; 3812 3813 PetscFunctionBeginHot; 3814 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3815 if (useCone) { 3816 PetscCall(DMPlexGetConeSize(dm, p, size)); 3817 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3818 } else { 3819 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3820 PetscCall(DMPlexGetSupport(dm, p, arr)); 3821 } 3822 } else { 3823 if (useCone) { 3824 const PetscSection s = mesh->coneSection; 3825 const PetscInt ps = p - s->pStart; 3826 const PetscInt off = s->atlasOff[ps]; 3827 3828 *size = s->atlasDof[ps]; 3829 *arr = mesh->cones + off; 3830 *ornt = mesh->coneOrientations + off; 3831 } else { 3832 const PetscSection s = mesh->supportSection; 3833 const PetscInt ps = p - s->pStart; 3834 const PetscInt off = s->atlasOff[ps]; 3835 3836 *size = s->atlasDof[ps]; 3837 *arr = mesh->supports + off; 3838 } 3839 } 3840 PetscFunctionReturn(PETSC_SUCCESS); 3841 } 3842 3843 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3844 { 3845 DM_Plex *mesh = (DM_Plex *)dm->data; 3846 3847 PetscFunctionBeginHot; 3848 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3849 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3850 } 3851 PetscFunctionReturn(PETSC_SUCCESS); 3852 } 3853 3854 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3855 { 3856 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3857 PetscInt *closure; 3858 const PetscInt *tmp = NULL, *tmpO = NULL; 3859 PetscInt off = 0, tmpSize, t; 3860 3861 PetscFunctionBeginHot; 3862 if (ornt) { 3863 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3864 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; 3865 } 3866 if (*points) { 3867 closure = *points; 3868 } else { 3869 PetscInt maxConeSize, maxSupportSize; 3870 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3871 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3872 } 3873 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3874 if (ct == DM_POLYTOPE_UNKNOWN) { 3875 closure[off++] = p; 3876 closure[off++] = 0; 3877 for (t = 0; t < tmpSize; ++t) { 3878 closure[off++] = tmp[t]; 3879 closure[off++] = tmpO ? tmpO[t] : 0; 3880 } 3881 } else { 3882 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3883 3884 /* We assume that cells with a valid type have faces with a valid type */ 3885 closure[off++] = p; 3886 closure[off++] = ornt; 3887 for (t = 0; t < tmpSize; ++t) { 3888 DMPolytopeType ft; 3889 3890 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3891 closure[off++] = tmp[arr[t]]; 3892 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3893 } 3894 } 3895 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3896 if (numPoints) *numPoints = tmpSize + 1; 3897 if (points) *points = closure; 3898 PetscFunctionReturn(PETSC_SUCCESS); 3899 } 3900 3901 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3902 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3903 { 3904 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3905 const PetscInt *cone, *ornt; 3906 PetscInt *pts, *closure = NULL; 3907 DMPolytopeType ft; 3908 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3909 PetscInt dim, coneSize, c, d, clSize, cl; 3910 3911 PetscFunctionBeginHot; 3912 PetscCall(DMGetDimension(dm, &dim)); 3913 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3914 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3915 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3916 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3917 maxSize = PetscMax(coneSeries, supportSeries); 3918 if (*points) { 3919 pts = *points; 3920 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3921 c = 0; 3922 pts[c++] = point; 3923 pts[c++] = o; 3924 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3925 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3926 for (cl = 0; cl < clSize * 2; cl += 2) { 3927 pts[c++] = closure[cl]; 3928 pts[c++] = closure[cl + 1]; 3929 } 3930 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3931 for (cl = 0; cl < clSize * 2; cl += 2) { 3932 pts[c++] = closure[cl]; 3933 pts[c++] = closure[cl + 1]; 3934 } 3935 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3936 for (d = 2; d < coneSize; ++d) { 3937 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3938 pts[c++] = cone[arr[d * 2 + 0]]; 3939 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3940 } 3941 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3942 if (dim >= 3) { 3943 for (d = 2; d < coneSize; ++d) { 3944 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3945 const PetscInt *fcone, *fornt; 3946 PetscInt fconeSize, fc, i; 3947 3948 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3949 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3950 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3951 for (fc = 0; fc < fconeSize; ++fc) { 3952 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3953 const PetscInt co = farr[fc * 2 + 1]; 3954 3955 for (i = 0; i < c; i += 2) 3956 if (pts[i] == cp) break; 3957 if (i == c) { 3958 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3959 pts[c++] = cp; 3960 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3961 } 3962 } 3963 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3964 } 3965 } 3966 *numPoints = c / 2; 3967 *points = pts; 3968 PetscFunctionReturn(PETSC_SUCCESS); 3969 } 3970 3971 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3972 { 3973 DMPolytopeType ct; 3974 PetscInt *closure, *fifo; 3975 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3976 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3977 PetscInt depth, maxSize; 3978 3979 PetscFunctionBeginHot; 3980 PetscCall(DMPlexGetDepth(dm, &depth)); 3981 if (depth == 1) { 3982 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3983 PetscFunctionReturn(PETSC_SUCCESS); 3984 } 3985 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3986 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; 3987 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3988 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3989 PetscFunctionReturn(PETSC_SUCCESS); 3990 } 3991 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3992 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3993 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3994 maxSize = PetscMax(coneSeries, supportSeries); 3995 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3996 if (*points) { 3997 closure = *points; 3998 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3999 closure[closureSize++] = p; 4000 closure[closureSize++] = ornt; 4001 fifo[fifoSize++] = p; 4002 fifo[fifoSize++] = ornt; 4003 fifo[fifoSize++] = ct; 4004 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4005 while (fifoSize - fifoStart) { 4006 const PetscInt q = fifo[fifoStart++]; 4007 const PetscInt o = fifo[fifoStart++]; 4008 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4009 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4010 const PetscInt *tmp, *tmpO = NULL; 4011 PetscInt tmpSize, t; 4012 4013 if (PetscDefined(USE_DEBUG)) { 4014 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4015 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); 4016 } 4017 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4018 for (t = 0; t < tmpSize; ++t) { 4019 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4020 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4021 const PetscInt cp = tmp[ip]; 4022 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4023 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4024 PetscInt c; 4025 4026 /* Check for duplicate */ 4027 for (c = 0; c < closureSize; c += 2) { 4028 if (closure[c] == cp) break; 4029 } 4030 if (c == closureSize) { 4031 closure[closureSize++] = cp; 4032 closure[closureSize++] = co; 4033 fifo[fifoSize++] = cp; 4034 fifo[fifoSize++] = co; 4035 fifo[fifoSize++] = ct; 4036 } 4037 } 4038 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4039 } 4040 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4041 if (numPoints) *numPoints = closureSize / 2; 4042 if (points) *points = closure; 4043 PetscFunctionReturn(PETSC_SUCCESS); 4044 } 4045 4046 /*@C 4047 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4048 4049 Not Collective 4050 4051 Input Parameters: 4052 + dm - The `DMPLEX` 4053 . p - The mesh point 4054 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4055 4056 Input/Output Parameter: 4057 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4058 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4059 4060 Output Parameter: 4061 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4062 4063 Level: beginner 4064 4065 Note: 4066 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4067 4068 Fortran Notes: 4069 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4070 4071 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4072 @*/ 4073 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4074 { 4075 PetscFunctionBeginHot; 4076 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4077 if (numPoints) PetscAssertPointer(numPoints, 4); 4078 if (points) PetscAssertPointer(points, 5); 4079 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4080 PetscFunctionReturn(PETSC_SUCCESS); 4081 } 4082 4083 /*@C 4084 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4085 4086 Not Collective 4087 4088 Input Parameters: 4089 + dm - The `DMPLEX` 4090 . p - The mesh point 4091 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4092 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4093 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4094 4095 Level: beginner 4096 4097 Note: 4098 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4099 4100 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4101 @*/ 4102 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4103 { 4104 PetscFunctionBeginHot; 4105 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4106 if (numPoints) *numPoints = 0; 4107 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4108 PetscFunctionReturn(PETSC_SUCCESS); 4109 } 4110 4111 /*@ 4112 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4113 4114 Not Collective 4115 4116 Input Parameter: 4117 . dm - The `DMPLEX` 4118 4119 Output Parameters: 4120 + maxConeSize - The maximum number of in-edges 4121 - maxSupportSize - The maximum number of out-edges 4122 4123 Level: beginner 4124 4125 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4126 @*/ 4127 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4128 { 4129 DM_Plex *mesh = (DM_Plex *)dm->data; 4130 4131 PetscFunctionBegin; 4132 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4133 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4134 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4135 PetscFunctionReturn(PETSC_SUCCESS); 4136 } 4137 4138 PetscErrorCode DMSetUp_Plex(DM dm) 4139 { 4140 DM_Plex *mesh = (DM_Plex *)dm->data; 4141 PetscInt size, maxSupportSize; 4142 4143 PetscFunctionBegin; 4144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4145 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4146 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4147 PetscCall(PetscMalloc1(size, &mesh->cones)); 4148 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4149 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4150 if (maxSupportSize) { 4151 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4152 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4153 PetscCall(PetscMalloc1(size, &mesh->supports)); 4154 } 4155 PetscFunctionReturn(PETSC_SUCCESS); 4156 } 4157 4158 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4159 { 4160 PetscFunctionBegin; 4161 if (subdm) PetscCall(DMClone(dm, subdm)); 4162 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4163 if (subdm) (*subdm)->useNatural = dm->useNatural; 4164 if (dm->useNatural && dm->sfMigration) { 4165 PetscSF sfNatural; 4166 4167 (*subdm)->sfMigration = dm->sfMigration; 4168 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4169 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4170 (*subdm)->sfNatural = sfNatural; 4171 } 4172 PetscFunctionReturn(PETSC_SUCCESS); 4173 } 4174 4175 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4176 { 4177 PetscInt i = 0; 4178 4179 PetscFunctionBegin; 4180 PetscCall(DMClone(dms[0], superdm)); 4181 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4182 (*superdm)->useNatural = PETSC_FALSE; 4183 for (i = 0; i < len; i++) { 4184 if (dms[i]->useNatural && dms[i]->sfMigration) { 4185 PetscSF sfNatural; 4186 4187 (*superdm)->sfMigration = dms[i]->sfMigration; 4188 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4189 (*superdm)->useNatural = PETSC_TRUE; 4190 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4191 (*superdm)->sfNatural = sfNatural; 4192 break; 4193 } 4194 } 4195 PetscFunctionReturn(PETSC_SUCCESS); 4196 } 4197 4198 /*@ 4199 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4200 4201 Not Collective 4202 4203 Input Parameter: 4204 . dm - The `DMPLEX` 4205 4206 Level: beginner 4207 4208 Note: 4209 This should be called after all calls to `DMPlexSetCone()` 4210 4211 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4212 @*/ 4213 PetscErrorCode DMPlexSymmetrize(DM dm) 4214 { 4215 DM_Plex *mesh = (DM_Plex *)dm->data; 4216 PetscInt *offsets; 4217 PetscInt supportSize; 4218 PetscInt pStart, pEnd, p; 4219 4220 PetscFunctionBegin; 4221 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4222 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4223 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4224 /* Calculate support sizes */ 4225 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4226 for (p = pStart; p < pEnd; ++p) { 4227 PetscInt dof, off, c; 4228 4229 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4230 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4231 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4232 } 4233 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4234 /* Calculate supports */ 4235 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4236 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4237 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4238 for (p = pStart; p < pEnd; ++p) { 4239 PetscInt dof, off, c; 4240 4241 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4242 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4243 for (c = off; c < off + dof; ++c) { 4244 const PetscInt q = mesh->cones[c]; 4245 PetscInt offS; 4246 4247 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4248 4249 mesh->supports[offS + offsets[q]] = p; 4250 ++offsets[q]; 4251 } 4252 } 4253 PetscCall(PetscFree(offsets)); 4254 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4255 PetscFunctionReturn(PETSC_SUCCESS); 4256 } 4257 4258 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4259 { 4260 IS stratumIS; 4261 4262 PetscFunctionBegin; 4263 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4264 if (PetscDefined(USE_DEBUG)) { 4265 PetscInt qStart, qEnd, numLevels, level; 4266 PetscBool overlap = PETSC_FALSE; 4267 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4268 for (level = 0; level < numLevels; level++) { 4269 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4270 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4271 overlap = PETSC_TRUE; 4272 break; 4273 } 4274 } 4275 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); 4276 } 4277 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4278 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4279 PetscCall(ISDestroy(&stratumIS)); 4280 PetscFunctionReturn(PETSC_SUCCESS); 4281 } 4282 4283 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4284 { 4285 PetscInt *pMin, *pMax; 4286 PetscInt pStart, pEnd; 4287 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4288 4289 PetscFunctionBegin; 4290 { 4291 DMLabel label2; 4292 4293 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4294 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4295 } 4296 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4297 for (PetscInt p = pStart; p < pEnd; ++p) { 4298 DMPolytopeType ct; 4299 4300 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4301 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4302 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4303 } 4304 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4305 for (PetscInt d = dmin; d <= dmax; ++d) { 4306 pMin[d] = PETSC_MAX_INT; 4307 pMax[d] = PETSC_MIN_INT; 4308 } 4309 for (PetscInt p = pStart; p < pEnd; ++p) { 4310 DMPolytopeType ct; 4311 PetscInt d; 4312 4313 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4314 d = DMPolytopeTypeGetDim(ct); 4315 pMin[d] = PetscMin(p, pMin[d]); 4316 pMax[d] = PetscMax(p, pMax[d]); 4317 } 4318 for (PetscInt d = dmin; d <= dmax; ++d) { 4319 if (pMin[d] > pMax[d]) continue; 4320 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4321 } 4322 PetscCall(PetscFree2(pMin, pMax)); 4323 PetscFunctionReturn(PETSC_SUCCESS); 4324 } 4325 4326 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4327 { 4328 PetscInt pStart, pEnd; 4329 PetscInt numRoots = 0, numLeaves = 0; 4330 4331 PetscFunctionBegin; 4332 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4333 { 4334 /* Initialize roots and count leaves */ 4335 PetscInt sMin = PETSC_MAX_INT; 4336 PetscInt sMax = PETSC_MIN_INT; 4337 PetscInt coneSize, supportSize; 4338 4339 for (PetscInt p = pStart; p < pEnd; ++p) { 4340 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4341 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4342 if (!coneSize && supportSize) { 4343 sMin = PetscMin(p, sMin); 4344 sMax = PetscMax(p, sMax); 4345 ++numRoots; 4346 } else if (!supportSize && coneSize) { 4347 ++numLeaves; 4348 } else if (!supportSize && !coneSize) { 4349 /* Isolated points */ 4350 sMin = PetscMin(p, sMin); 4351 sMax = PetscMax(p, sMax); 4352 } 4353 } 4354 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4355 } 4356 4357 if (numRoots + numLeaves == (pEnd - pStart)) { 4358 PetscInt sMin = PETSC_MAX_INT; 4359 PetscInt sMax = PETSC_MIN_INT; 4360 PetscInt coneSize, supportSize; 4361 4362 for (PetscInt p = pStart; p < pEnd; ++p) { 4363 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4364 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4365 if (!supportSize && coneSize) { 4366 sMin = PetscMin(p, sMin); 4367 sMax = PetscMax(p, sMax); 4368 } 4369 } 4370 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4371 } else { 4372 PetscInt level = 0; 4373 PetscInt qStart, qEnd; 4374 4375 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4376 while (qEnd > qStart) { 4377 PetscInt sMin = PETSC_MAX_INT; 4378 PetscInt sMax = PETSC_MIN_INT; 4379 4380 for (PetscInt q = qStart; q < qEnd; ++q) { 4381 const PetscInt *support; 4382 PetscInt supportSize; 4383 4384 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4385 PetscCall(DMPlexGetSupport(dm, q, &support)); 4386 for (PetscInt s = 0; s < supportSize; ++s) { 4387 sMin = PetscMin(support[s], sMin); 4388 sMax = PetscMax(support[s], sMax); 4389 } 4390 } 4391 PetscCall(DMLabelGetNumValues(label, &level)); 4392 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4393 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4394 } 4395 } 4396 PetscFunctionReturn(PETSC_SUCCESS); 4397 } 4398 4399 /*@ 4400 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4401 4402 Collective 4403 4404 Input Parameter: 4405 . dm - The `DMPLEX` 4406 4407 Level: beginner 4408 4409 Notes: 4410 The strata group all points of the same grade, and this function calculates the strata. This 4411 grade can be seen as the height (or depth) of the point in the DAG. 4412 4413 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4414 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4415 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4416 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4417 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4418 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4419 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4420 4421 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4422 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4423 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 4424 to interpolate only that one (e0), so that 4425 .vb 4426 cone(c0) = {e0, v2} 4427 cone(e0) = {v0, v1} 4428 .ve 4429 If `DMPlexStratify()` is run on this mesh, it will give depths 4430 .vb 4431 depth 0 = {v0, v1, v2} 4432 depth 1 = {e0, c0} 4433 .ve 4434 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4435 4436 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4437 4438 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4439 @*/ 4440 PetscErrorCode DMPlexStratify(DM dm) 4441 { 4442 DM_Plex *mesh = (DM_Plex *)dm->data; 4443 DMLabel label; 4444 PetscBool flg = PETSC_FALSE; 4445 4446 PetscFunctionBegin; 4447 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4448 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4449 4450 // Create depth label 4451 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4452 PetscCall(DMCreateLabel(dm, "depth")); 4453 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4454 4455 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4456 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4457 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4458 4459 { /* just in case there is an empty process */ 4460 PetscInt numValues, maxValues = 0, v; 4461 4462 PetscCall(DMLabelGetNumValues(label, &numValues)); 4463 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4464 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4465 } 4466 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4467 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4468 PetscFunctionReturn(PETSC_SUCCESS); 4469 } 4470 4471 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4472 { 4473 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4474 PetscInt dim, depth, pheight, coneSize; 4475 4476 PetscFunctionBeginHot; 4477 PetscCall(DMGetDimension(dm, &dim)); 4478 PetscCall(DMPlexGetDepth(dm, &depth)); 4479 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4480 pheight = depth - pdepth; 4481 if (depth <= 1) { 4482 switch (pdepth) { 4483 case 0: 4484 ct = DM_POLYTOPE_POINT; 4485 break; 4486 case 1: 4487 switch (coneSize) { 4488 case 2: 4489 ct = DM_POLYTOPE_SEGMENT; 4490 break; 4491 case 3: 4492 ct = DM_POLYTOPE_TRIANGLE; 4493 break; 4494 case 4: 4495 switch (dim) { 4496 case 2: 4497 ct = DM_POLYTOPE_QUADRILATERAL; 4498 break; 4499 case 3: 4500 ct = DM_POLYTOPE_TETRAHEDRON; 4501 break; 4502 default: 4503 break; 4504 } 4505 break; 4506 case 5: 4507 ct = DM_POLYTOPE_PYRAMID; 4508 break; 4509 case 6: 4510 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4511 break; 4512 case 8: 4513 ct = DM_POLYTOPE_HEXAHEDRON; 4514 break; 4515 default: 4516 break; 4517 } 4518 } 4519 } else { 4520 if (pdepth == 0) { 4521 ct = DM_POLYTOPE_POINT; 4522 } else if (pheight == 0) { 4523 switch (dim) { 4524 case 1: 4525 switch (coneSize) { 4526 case 2: 4527 ct = DM_POLYTOPE_SEGMENT; 4528 break; 4529 default: 4530 break; 4531 } 4532 break; 4533 case 2: 4534 switch (coneSize) { 4535 case 3: 4536 ct = DM_POLYTOPE_TRIANGLE; 4537 break; 4538 case 4: 4539 ct = DM_POLYTOPE_QUADRILATERAL; 4540 break; 4541 default: 4542 break; 4543 } 4544 break; 4545 case 3: 4546 switch (coneSize) { 4547 case 4: 4548 ct = DM_POLYTOPE_TETRAHEDRON; 4549 break; 4550 case 5: { 4551 const PetscInt *cone; 4552 PetscInt faceConeSize; 4553 4554 PetscCall(DMPlexGetCone(dm, p, &cone)); 4555 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4556 switch (faceConeSize) { 4557 case 3: 4558 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4559 break; 4560 case 4: 4561 ct = DM_POLYTOPE_PYRAMID; 4562 break; 4563 } 4564 } break; 4565 case 6: 4566 ct = DM_POLYTOPE_HEXAHEDRON; 4567 break; 4568 default: 4569 break; 4570 } 4571 break; 4572 default: 4573 break; 4574 } 4575 } else if (pheight > 0) { 4576 switch (coneSize) { 4577 case 2: 4578 ct = DM_POLYTOPE_SEGMENT; 4579 break; 4580 case 3: 4581 ct = DM_POLYTOPE_TRIANGLE; 4582 break; 4583 case 4: 4584 ct = DM_POLYTOPE_QUADRILATERAL; 4585 break; 4586 default: 4587 break; 4588 } 4589 } 4590 } 4591 *pt = ct; 4592 PetscFunctionReturn(PETSC_SUCCESS); 4593 } 4594 4595 /*@ 4596 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4597 4598 Collective 4599 4600 Input Parameter: 4601 . dm - The `DMPLEX` 4602 4603 Level: developer 4604 4605 Note: 4606 This function is normally called automatically when a cell type is requested. It creates an 4607 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4608 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4609 4610 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4611 4612 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4613 @*/ 4614 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4615 { 4616 DM_Plex *mesh; 4617 DMLabel ctLabel; 4618 PetscInt pStart, pEnd, p; 4619 4620 PetscFunctionBegin; 4621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4622 mesh = (DM_Plex *)dm->data; 4623 PetscCall(DMCreateLabel(dm, "celltype")); 4624 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4625 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4626 PetscCall(PetscFree(mesh->cellTypes)); 4627 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4628 for (p = pStart; p < pEnd; ++p) { 4629 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4630 PetscInt pdepth; 4631 4632 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4633 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4634 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); 4635 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4636 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4637 } 4638 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4639 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4640 PetscFunctionReturn(PETSC_SUCCESS); 4641 } 4642 4643 /*@C 4644 DMPlexGetJoin - Get an array for the join of the set of points 4645 4646 Not Collective 4647 4648 Input Parameters: 4649 + dm - The `DMPLEX` object 4650 . numPoints - The number of input points for the join 4651 - points - The input points 4652 4653 Output Parameters: 4654 + numCoveredPoints - The number of points in the join 4655 - coveredPoints - The points in the join 4656 4657 Level: intermediate 4658 4659 Note: 4660 Currently, this is restricted to a single level join 4661 4662 Fortran Notes: 4663 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4664 4665 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4666 @*/ 4667 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4668 { 4669 DM_Plex *mesh = (DM_Plex *)dm->data; 4670 PetscInt *join[2]; 4671 PetscInt joinSize, i = 0; 4672 PetscInt dof, off, p, c, m; 4673 PetscInt maxSupportSize; 4674 4675 PetscFunctionBegin; 4676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4677 PetscAssertPointer(points, 3); 4678 PetscAssertPointer(numCoveredPoints, 4); 4679 PetscAssertPointer(coveredPoints, 5); 4680 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4681 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4682 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4683 /* Copy in support of first point */ 4684 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4685 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4686 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4687 /* Check each successive support */ 4688 for (p = 1; p < numPoints; ++p) { 4689 PetscInt newJoinSize = 0; 4690 4691 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4692 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4693 for (c = 0; c < dof; ++c) { 4694 const PetscInt point = mesh->supports[off + c]; 4695 4696 for (m = 0; m < joinSize; ++m) { 4697 if (point == join[i][m]) { 4698 join[1 - i][newJoinSize++] = point; 4699 break; 4700 } 4701 } 4702 } 4703 joinSize = newJoinSize; 4704 i = 1 - i; 4705 } 4706 *numCoveredPoints = joinSize; 4707 *coveredPoints = join[i]; 4708 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4709 PetscFunctionReturn(PETSC_SUCCESS); 4710 } 4711 4712 /*@C 4713 DMPlexRestoreJoin - Restore an array for the join of the set of points 4714 4715 Not Collective 4716 4717 Input Parameters: 4718 + dm - The `DMPLEX` object 4719 . numPoints - The number of input points for the join 4720 - points - The input points 4721 4722 Output Parameters: 4723 + numCoveredPoints - The number of points in the join 4724 - coveredPoints - The points in the join 4725 4726 Level: intermediate 4727 4728 Fortran Notes: 4729 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4730 4731 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4732 @*/ 4733 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4734 { 4735 PetscFunctionBegin; 4736 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4737 if (points) PetscAssertPointer(points, 3); 4738 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4739 PetscAssertPointer(coveredPoints, 5); 4740 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4741 if (numCoveredPoints) *numCoveredPoints = 0; 4742 PetscFunctionReturn(PETSC_SUCCESS); 4743 } 4744 4745 /*@C 4746 DMPlexGetFullJoin - Get an array for the join of the set of points 4747 4748 Not Collective 4749 4750 Input Parameters: 4751 + dm - The `DMPLEX` object 4752 . numPoints - The number of input points for the join 4753 - points - The input points 4754 4755 Output Parameters: 4756 + numCoveredPoints - The number of points in the join 4757 - coveredPoints - The points in the join 4758 4759 Level: intermediate 4760 4761 Fortran Notes: 4762 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4763 4764 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4765 @*/ 4766 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4767 { 4768 PetscInt *offsets, **closures; 4769 PetscInt *join[2]; 4770 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4771 PetscInt p, d, c, m, ms; 4772 4773 PetscFunctionBegin; 4774 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4775 PetscAssertPointer(points, 3); 4776 PetscAssertPointer(numCoveredPoints, 4); 4777 PetscAssertPointer(coveredPoints, 5); 4778 4779 PetscCall(DMPlexGetDepth(dm, &depth)); 4780 PetscCall(PetscCalloc1(numPoints, &closures)); 4781 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4782 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4783 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4784 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4785 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4786 4787 for (p = 0; p < numPoints; ++p) { 4788 PetscInt closureSize; 4789 4790 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4791 4792 offsets[p * (depth + 2) + 0] = 0; 4793 for (d = 0; d < depth + 1; ++d) { 4794 PetscInt pStart, pEnd, i; 4795 4796 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4797 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4798 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4799 offsets[p * (depth + 2) + d + 1] = i; 4800 break; 4801 } 4802 } 4803 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4804 } 4805 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); 4806 } 4807 for (d = 0; d < depth + 1; ++d) { 4808 PetscInt dof; 4809 4810 /* Copy in support of first point */ 4811 dof = offsets[d + 1] - offsets[d]; 4812 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4813 /* Check each successive cone */ 4814 for (p = 1; p < numPoints && joinSize; ++p) { 4815 PetscInt newJoinSize = 0; 4816 4817 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4818 for (c = 0; c < dof; ++c) { 4819 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4820 4821 for (m = 0; m < joinSize; ++m) { 4822 if (point == join[i][m]) { 4823 join[1 - i][newJoinSize++] = point; 4824 break; 4825 } 4826 } 4827 } 4828 joinSize = newJoinSize; 4829 i = 1 - i; 4830 } 4831 if (joinSize) break; 4832 } 4833 *numCoveredPoints = joinSize; 4834 *coveredPoints = join[i]; 4835 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4836 PetscCall(PetscFree(closures)); 4837 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4838 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4839 PetscFunctionReturn(PETSC_SUCCESS); 4840 } 4841 4842 /*@C 4843 DMPlexGetMeet - Get an array for the meet of the set of points 4844 4845 Not Collective 4846 4847 Input Parameters: 4848 + dm - The `DMPLEX` object 4849 . numPoints - The number of input points for the meet 4850 - points - The input points 4851 4852 Output Parameters: 4853 + numCoveringPoints - The number of points in the meet 4854 - coveringPoints - The points in the meet 4855 4856 Level: intermediate 4857 4858 Note: 4859 Currently, this is restricted to a single level meet 4860 4861 Fortran Notes: 4862 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4863 4864 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4865 @*/ 4866 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4867 { 4868 DM_Plex *mesh = (DM_Plex *)dm->data; 4869 PetscInt *meet[2]; 4870 PetscInt meetSize, i = 0; 4871 PetscInt dof, off, p, c, m; 4872 PetscInt maxConeSize; 4873 4874 PetscFunctionBegin; 4875 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4876 PetscAssertPointer(points, 3); 4877 PetscAssertPointer(numCoveringPoints, 4); 4878 PetscAssertPointer(coveringPoints, 5); 4879 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4880 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4881 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4882 /* Copy in cone of first point */ 4883 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4884 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4885 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4886 /* Check each successive cone */ 4887 for (p = 1; p < numPoints; ++p) { 4888 PetscInt newMeetSize = 0; 4889 4890 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4891 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4892 for (c = 0; c < dof; ++c) { 4893 const PetscInt point = mesh->cones[off + c]; 4894 4895 for (m = 0; m < meetSize; ++m) { 4896 if (point == meet[i][m]) { 4897 meet[1 - i][newMeetSize++] = point; 4898 break; 4899 } 4900 } 4901 } 4902 meetSize = newMeetSize; 4903 i = 1 - i; 4904 } 4905 *numCoveringPoints = meetSize; 4906 *coveringPoints = meet[i]; 4907 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4908 PetscFunctionReturn(PETSC_SUCCESS); 4909 } 4910 4911 /*@C 4912 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4913 4914 Not Collective 4915 4916 Input Parameters: 4917 + dm - The `DMPLEX` object 4918 . numPoints - The number of input points for the meet 4919 - points - The input points 4920 4921 Output Parameters: 4922 + numCoveredPoints - The number of points in the meet 4923 - coveredPoints - The points in the meet 4924 4925 Level: intermediate 4926 4927 Fortran Notes: 4928 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4929 4930 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4931 @*/ 4932 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4933 { 4934 PetscFunctionBegin; 4935 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4936 if (points) PetscAssertPointer(points, 3); 4937 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4938 PetscAssertPointer(coveredPoints, 5); 4939 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4940 if (numCoveredPoints) *numCoveredPoints = 0; 4941 PetscFunctionReturn(PETSC_SUCCESS); 4942 } 4943 4944 /*@C 4945 DMPlexGetFullMeet - Get an array for the meet of the set of points 4946 4947 Not Collective 4948 4949 Input Parameters: 4950 + dm - The `DMPLEX` object 4951 . numPoints - The number of input points for the meet 4952 - points - The input points 4953 4954 Output Parameters: 4955 + numCoveredPoints - The number of points in the meet 4956 - coveredPoints - The points in the meet 4957 4958 Level: intermediate 4959 4960 Fortran Notes: 4961 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4962 4963 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4964 @*/ 4965 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4966 { 4967 PetscInt *offsets, **closures; 4968 PetscInt *meet[2]; 4969 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4970 PetscInt p, h, c, m, mc; 4971 4972 PetscFunctionBegin; 4973 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4974 PetscAssertPointer(points, 3); 4975 PetscAssertPointer(numCoveredPoints, 4); 4976 PetscAssertPointer(coveredPoints, 5); 4977 4978 PetscCall(DMPlexGetDepth(dm, &height)); 4979 PetscCall(PetscMalloc1(numPoints, &closures)); 4980 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4981 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4982 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4983 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4984 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4985 4986 for (p = 0; p < numPoints; ++p) { 4987 PetscInt closureSize; 4988 4989 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4990 4991 offsets[p * (height + 2) + 0] = 0; 4992 for (h = 0; h < height + 1; ++h) { 4993 PetscInt pStart, pEnd, i; 4994 4995 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4996 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4997 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4998 offsets[p * (height + 2) + h + 1] = i; 4999 break; 5000 } 5001 } 5002 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5003 } 5004 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); 5005 } 5006 for (h = 0; h < height + 1; ++h) { 5007 PetscInt dof; 5008 5009 /* Copy in cone of first point */ 5010 dof = offsets[h + 1] - offsets[h]; 5011 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5012 /* Check each successive cone */ 5013 for (p = 1; p < numPoints && meetSize; ++p) { 5014 PetscInt newMeetSize = 0; 5015 5016 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5017 for (c = 0; c < dof; ++c) { 5018 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5019 5020 for (m = 0; m < meetSize; ++m) { 5021 if (point == meet[i][m]) { 5022 meet[1 - i][newMeetSize++] = point; 5023 break; 5024 } 5025 } 5026 } 5027 meetSize = newMeetSize; 5028 i = 1 - i; 5029 } 5030 if (meetSize) break; 5031 } 5032 *numCoveredPoints = meetSize; 5033 *coveredPoints = meet[i]; 5034 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5035 PetscCall(PetscFree(closures)); 5036 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5037 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5038 PetscFunctionReturn(PETSC_SUCCESS); 5039 } 5040 5041 /*@C 5042 DMPlexEqual - Determine if two `DM` have the same topology 5043 5044 Not Collective 5045 5046 Input Parameters: 5047 + dmA - A `DMPLEX` object 5048 - dmB - A `DMPLEX` object 5049 5050 Output Parameter: 5051 . equal - `PETSC_TRUE` if the topologies are identical 5052 5053 Level: intermediate 5054 5055 Note: 5056 We are not solving graph isomorphism, so we do not permute. 5057 5058 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5059 @*/ 5060 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5061 { 5062 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5063 5064 PetscFunctionBegin; 5065 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5066 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5067 PetscAssertPointer(equal, 3); 5068 5069 *equal = PETSC_FALSE; 5070 PetscCall(DMPlexGetDepth(dmA, &depth)); 5071 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5072 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5073 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5074 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5075 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5076 for (p = pStart; p < pEnd; ++p) { 5077 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5078 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5079 5080 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5081 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5082 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5083 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5084 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5085 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5086 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5087 for (c = 0; c < coneSize; ++c) { 5088 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5089 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5090 } 5091 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5092 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5093 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5094 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5095 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5096 for (s = 0; s < supportSize; ++s) { 5097 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5098 } 5099 } 5100 *equal = PETSC_TRUE; 5101 PetscFunctionReturn(PETSC_SUCCESS); 5102 } 5103 5104 /*@C 5105 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5106 5107 Not Collective 5108 5109 Input Parameters: 5110 + dm - The `DMPLEX` 5111 . cellDim - The cell dimension 5112 - numCorners - The number of vertices on a cell 5113 5114 Output Parameter: 5115 . numFaceVertices - The number of vertices on a face 5116 5117 Level: developer 5118 5119 Note: 5120 Of course this can only work for a restricted set of symmetric shapes 5121 5122 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5123 @*/ 5124 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5125 { 5126 MPI_Comm comm; 5127 5128 PetscFunctionBegin; 5129 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5130 PetscAssertPointer(numFaceVertices, 4); 5131 switch (cellDim) { 5132 case 0: 5133 *numFaceVertices = 0; 5134 break; 5135 case 1: 5136 *numFaceVertices = 1; 5137 break; 5138 case 2: 5139 switch (numCorners) { 5140 case 3: /* triangle */ 5141 *numFaceVertices = 2; /* Edge has 2 vertices */ 5142 break; 5143 case 4: /* quadrilateral */ 5144 *numFaceVertices = 2; /* Edge has 2 vertices */ 5145 break; 5146 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5147 *numFaceVertices = 3; /* Edge has 3 vertices */ 5148 break; 5149 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5150 *numFaceVertices = 3; /* Edge has 3 vertices */ 5151 break; 5152 default: 5153 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5154 } 5155 break; 5156 case 3: 5157 switch (numCorners) { 5158 case 4: /* tetradehdron */ 5159 *numFaceVertices = 3; /* Face has 3 vertices */ 5160 break; 5161 case 6: /* tet cohesive cells */ 5162 *numFaceVertices = 4; /* Face has 4 vertices */ 5163 break; 5164 case 8: /* hexahedron */ 5165 *numFaceVertices = 4; /* Face has 4 vertices */ 5166 break; 5167 case 9: /* tet cohesive Lagrange cells */ 5168 *numFaceVertices = 6; /* Face has 6 vertices */ 5169 break; 5170 case 10: /* quadratic tetrahedron */ 5171 *numFaceVertices = 6; /* Face has 6 vertices */ 5172 break; 5173 case 12: /* hex cohesive Lagrange cells */ 5174 *numFaceVertices = 6; /* Face has 6 vertices */ 5175 break; 5176 case 18: /* quadratic tet cohesive Lagrange cells */ 5177 *numFaceVertices = 6; /* Face has 6 vertices */ 5178 break; 5179 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5180 *numFaceVertices = 9; /* Face has 9 vertices */ 5181 break; 5182 default: 5183 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5184 } 5185 break; 5186 default: 5187 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5188 } 5189 PetscFunctionReturn(PETSC_SUCCESS); 5190 } 5191 5192 /*@ 5193 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5194 5195 Not Collective 5196 5197 Input Parameter: 5198 . dm - The `DMPLEX` object 5199 5200 Output Parameter: 5201 . depthLabel - The `DMLabel` recording point depth 5202 5203 Level: developer 5204 5205 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5206 @*/ 5207 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5208 { 5209 PetscFunctionBegin; 5210 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5211 PetscAssertPointer(depthLabel, 2); 5212 *depthLabel = dm->depthLabel; 5213 PetscFunctionReturn(PETSC_SUCCESS); 5214 } 5215 5216 /*@ 5217 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5218 5219 Not Collective 5220 5221 Input Parameter: 5222 . dm - The `DMPLEX` object 5223 5224 Output Parameter: 5225 . depth - The number of strata (breadth first levels) in the DAG 5226 5227 Level: developer 5228 5229 Notes: 5230 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5231 5232 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5233 5234 An empty mesh gives -1. 5235 5236 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5237 @*/ 5238 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5239 { 5240 DM_Plex *mesh = (DM_Plex *)dm->data; 5241 DMLabel label; 5242 PetscInt d = 0; 5243 5244 PetscFunctionBegin; 5245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5246 PetscAssertPointer(depth, 2); 5247 if (mesh->tr) { 5248 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5249 } else { 5250 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5251 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5252 *depth = d - 1; 5253 } 5254 PetscFunctionReturn(PETSC_SUCCESS); 5255 } 5256 5257 /*@ 5258 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5259 5260 Not Collective 5261 5262 Input Parameters: 5263 + dm - The `DMPLEX` object 5264 - depth - The requested depth 5265 5266 Output Parameters: 5267 + start - The first point at this `depth` 5268 - end - One beyond the last point at this `depth` 5269 5270 Level: developer 5271 5272 Notes: 5273 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5274 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5275 higher dimension, e.g., "edges". 5276 5277 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5278 @*/ 5279 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5280 { 5281 DM_Plex *mesh = (DM_Plex *)dm->data; 5282 DMLabel label; 5283 PetscInt pStart, pEnd; 5284 5285 PetscFunctionBegin; 5286 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5287 if (start) { 5288 PetscAssertPointer(start, 3); 5289 *start = 0; 5290 } 5291 if (end) { 5292 PetscAssertPointer(end, 4); 5293 *end = 0; 5294 } 5295 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5296 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5297 if (depth < 0) { 5298 if (start) *start = pStart; 5299 if (end) *end = pEnd; 5300 PetscFunctionReturn(PETSC_SUCCESS); 5301 } 5302 if (mesh->tr) { 5303 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5304 } else { 5305 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5306 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5307 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5308 } 5309 PetscFunctionReturn(PETSC_SUCCESS); 5310 } 5311 5312 /*@ 5313 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5314 5315 Not Collective 5316 5317 Input Parameters: 5318 + dm - The `DMPLEX` object 5319 - height - The requested height 5320 5321 Output Parameters: 5322 + start - The first point at this `height` 5323 - end - One beyond the last point at this `height` 5324 5325 Level: developer 5326 5327 Notes: 5328 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5329 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5330 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5331 5332 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5333 @*/ 5334 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5335 { 5336 DMLabel label; 5337 PetscInt depth, pStart, pEnd; 5338 5339 PetscFunctionBegin; 5340 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5341 if (start) { 5342 PetscAssertPointer(start, 3); 5343 *start = 0; 5344 } 5345 if (end) { 5346 PetscAssertPointer(end, 4); 5347 *end = 0; 5348 } 5349 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5350 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5351 if (height < 0) { 5352 if (start) *start = pStart; 5353 if (end) *end = pEnd; 5354 PetscFunctionReturn(PETSC_SUCCESS); 5355 } 5356 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5357 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5358 else PetscCall(DMGetDimension(dm, &depth)); 5359 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5360 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5361 PetscFunctionReturn(PETSC_SUCCESS); 5362 } 5363 5364 /*@ 5365 DMPlexGetPointDepth - Get the `depth` of a given point 5366 5367 Not Collective 5368 5369 Input Parameters: 5370 + dm - The `DMPLEX` object 5371 - point - The point 5372 5373 Output Parameter: 5374 . depth - The depth of the `point` 5375 5376 Level: intermediate 5377 5378 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5379 @*/ 5380 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5381 { 5382 PetscFunctionBegin; 5383 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5384 PetscAssertPointer(depth, 3); 5385 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5386 PetscFunctionReturn(PETSC_SUCCESS); 5387 } 5388 5389 /*@ 5390 DMPlexGetPointHeight - Get the `height` of a given point 5391 5392 Not Collective 5393 5394 Input Parameters: 5395 + dm - The `DMPLEX` object 5396 - point - The point 5397 5398 Output Parameter: 5399 . height - The height of the `point` 5400 5401 Level: intermediate 5402 5403 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5404 @*/ 5405 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5406 { 5407 PetscInt n, pDepth; 5408 5409 PetscFunctionBegin; 5410 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5411 PetscAssertPointer(height, 3); 5412 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5413 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5414 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5415 PetscFunctionReturn(PETSC_SUCCESS); 5416 } 5417 5418 /*@ 5419 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5420 5421 Not Collective 5422 5423 Input Parameter: 5424 . dm - The `DMPLEX` object 5425 5426 Output Parameter: 5427 . celltypeLabel - The `DMLabel` recording cell polytope type 5428 5429 Level: developer 5430 5431 Note: 5432 This function will trigger automatica computation of cell types. This can be disabled by calling 5433 `DMCreateLabel`(dm, "celltype") beforehand. 5434 5435 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5436 @*/ 5437 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5438 { 5439 PetscFunctionBegin; 5440 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5441 PetscAssertPointer(celltypeLabel, 2); 5442 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5443 *celltypeLabel = dm->celltypeLabel; 5444 PetscFunctionReturn(PETSC_SUCCESS); 5445 } 5446 5447 /*@ 5448 DMPlexGetCellType - Get the polytope type of a given cell 5449 5450 Not Collective 5451 5452 Input Parameters: 5453 + dm - The `DMPLEX` object 5454 - cell - The cell 5455 5456 Output Parameter: 5457 . celltype - The polytope type of the cell 5458 5459 Level: intermediate 5460 5461 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5462 @*/ 5463 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5464 { 5465 DM_Plex *mesh = (DM_Plex *)dm->data; 5466 DMLabel label; 5467 PetscInt ct; 5468 5469 PetscFunctionBegin; 5470 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5471 PetscAssertPointer(celltype, 3); 5472 if (mesh->tr) { 5473 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5474 } else { 5475 PetscInt pStart, pEnd; 5476 5477 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5478 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5479 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5480 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5481 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5482 for (PetscInt p = pStart; p < pEnd; p++) { 5483 PetscCall(DMLabelGetValue(label, p, &ct)); 5484 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5485 } 5486 } 5487 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5488 if (PetscDefined(USE_DEBUG)) { 5489 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5490 PetscCall(DMLabelGetValue(label, cell, &ct)); 5491 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5492 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5493 } 5494 } 5495 PetscFunctionReturn(PETSC_SUCCESS); 5496 } 5497 5498 /*@ 5499 DMPlexSetCellType - Set the polytope type of a given cell 5500 5501 Not Collective 5502 5503 Input Parameters: 5504 + dm - The `DMPLEX` object 5505 . cell - The cell 5506 - celltype - The polytope type of the cell 5507 5508 Level: advanced 5509 5510 Note: 5511 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5512 is executed. This function will override the computed type. However, if automatic classification will not succeed 5513 and a user wants to manually specify all types, the classification must be disabled by calling 5514 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5515 5516 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5517 @*/ 5518 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5519 { 5520 DM_Plex *mesh = (DM_Plex *)dm->data; 5521 DMLabel label; 5522 PetscInt pStart, pEnd; 5523 5524 PetscFunctionBegin; 5525 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5526 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5527 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5528 PetscCall(DMLabelSetValue(label, cell, celltype)); 5529 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5530 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5531 PetscFunctionReturn(PETSC_SUCCESS); 5532 } 5533 5534 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5535 { 5536 PetscSection section; 5537 PetscInt maxHeight; 5538 const char *prefix; 5539 5540 PetscFunctionBegin; 5541 PetscCall(DMClone(dm, cdm)); 5542 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5543 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5544 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5545 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5546 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5547 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5548 PetscCall(DMSetLocalSection(*cdm, section)); 5549 PetscCall(PetscSectionDestroy(§ion)); 5550 5551 PetscCall(DMSetNumFields(*cdm, 1)); 5552 PetscCall(DMCreateDS(*cdm)); 5553 (*cdm)->cloneOpts = PETSC_TRUE; 5554 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5555 PetscFunctionReturn(PETSC_SUCCESS); 5556 } 5557 5558 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5559 { 5560 Vec coordsLocal, cellCoordsLocal; 5561 DM coordsDM, cellCoordsDM; 5562 5563 PetscFunctionBegin; 5564 *field = NULL; 5565 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5566 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5567 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5568 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5569 if (coordsLocal && coordsDM) { 5570 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5571 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5572 } 5573 PetscFunctionReturn(PETSC_SUCCESS); 5574 } 5575 5576 /*@C 5577 DMPlexGetConeSection - Return a section which describes the layout of cone data 5578 5579 Not Collective 5580 5581 Input Parameter: 5582 . dm - The `DMPLEX` object 5583 5584 Output Parameter: 5585 . section - The `PetscSection` object 5586 5587 Level: developer 5588 5589 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5590 @*/ 5591 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5592 { 5593 DM_Plex *mesh = (DM_Plex *)dm->data; 5594 5595 PetscFunctionBegin; 5596 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5597 if (section) *section = mesh->coneSection; 5598 PetscFunctionReturn(PETSC_SUCCESS); 5599 } 5600 5601 /*@C 5602 DMPlexGetSupportSection - Return a section which describes the layout of support data 5603 5604 Not Collective 5605 5606 Input Parameter: 5607 . dm - The `DMPLEX` object 5608 5609 Output Parameter: 5610 . section - The `PetscSection` object 5611 5612 Level: developer 5613 5614 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5615 @*/ 5616 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5617 { 5618 DM_Plex *mesh = (DM_Plex *)dm->data; 5619 5620 PetscFunctionBegin; 5621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5622 if (section) *section = mesh->supportSection; 5623 PetscFunctionReturn(PETSC_SUCCESS); 5624 } 5625 5626 /*@C 5627 DMPlexGetCones - Return cone data 5628 5629 Not Collective 5630 5631 Input Parameter: 5632 . dm - The `DMPLEX` object 5633 5634 Output Parameter: 5635 . cones - The cone for each point 5636 5637 Level: developer 5638 5639 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5640 @*/ 5641 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5642 { 5643 DM_Plex *mesh = (DM_Plex *)dm->data; 5644 5645 PetscFunctionBegin; 5646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5647 if (cones) *cones = mesh->cones; 5648 PetscFunctionReturn(PETSC_SUCCESS); 5649 } 5650 5651 /*@C 5652 DMPlexGetConeOrientations - Return cone orientation data 5653 5654 Not Collective 5655 5656 Input Parameter: 5657 . dm - The `DMPLEX` object 5658 5659 Output Parameter: 5660 . coneOrientations - The array of cone orientations for all points 5661 5662 Level: developer 5663 5664 Notes: 5665 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5666 5667 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5668 5669 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5670 @*/ 5671 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5672 { 5673 DM_Plex *mesh = (DM_Plex *)dm->data; 5674 5675 PetscFunctionBegin; 5676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5677 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5678 PetscFunctionReturn(PETSC_SUCCESS); 5679 } 5680 5681 /******************************** FEM Support **********************************/ 5682 5683 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5684 { 5685 PetscInt depth; 5686 5687 PetscFunctionBegin; 5688 PetscCall(DMPlexGetDepth(plex, &depth)); 5689 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5690 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5691 PetscFunctionReturn(PETSC_SUCCESS); 5692 } 5693 5694 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5695 { 5696 PetscInt depth; 5697 5698 PetscFunctionBegin; 5699 PetscCall(DMPlexGetDepth(plex, &depth)); 5700 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5701 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5702 PetscFunctionReturn(PETSC_SUCCESS); 5703 } 5704 5705 /* 5706 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5707 representing a line in the section. 5708 */ 5709 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5710 { 5711 PetscObject obj; 5712 PetscClassId id; 5713 PetscFE fe = NULL; 5714 5715 PetscFunctionBeginHot; 5716 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5717 PetscCall(DMGetField(dm, field, NULL, &obj)); 5718 PetscCall(PetscObjectGetClassId(obj, &id)); 5719 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5720 5721 if (!fe) { 5722 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5723 /* An order k SEM disc has k-1 dofs on an edge */ 5724 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5725 *k = *k / *Nc + 1; 5726 } else { 5727 PetscInt dual_space_size, dim; 5728 PetscDualSpace dsp; 5729 5730 PetscCall(DMGetDimension(dm, &dim)); 5731 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5732 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5733 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5734 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5735 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5736 } 5737 PetscFunctionReturn(PETSC_SUCCESS); 5738 } 5739 5740 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5741 { 5742 PetscFunctionBeginHot; 5743 if (tensor) { 5744 *dof = PetscPowInt(k + 1, dim); 5745 } else { 5746 switch (dim) { 5747 case 1: 5748 *dof = k + 1; 5749 break; 5750 case 2: 5751 *dof = ((k + 1) * (k + 2)) / 2; 5752 break; 5753 case 3: 5754 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5755 break; 5756 default: 5757 *dof = 0; 5758 } 5759 } 5760 PetscFunctionReturn(PETSC_SUCCESS); 5761 } 5762 5763 /*@ 5764 5765 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5766 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5767 section provided (or the section of the `DM`). 5768 5769 Input Parameters: 5770 + dm - The `DM` 5771 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5772 - section - The `PetscSection` to reorder, or `NULL` for the default section 5773 5774 Example: 5775 A typical interpolated single-quad mesh might order points as 5776 .vb 5777 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5778 5779 v4 -- e6 -- v3 5780 | | 5781 e7 c0 e8 5782 | | 5783 v1 -- e5 -- v2 5784 .ve 5785 5786 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5787 dofs in the order of points, e.g., 5788 .vb 5789 c0 -> [0,1,2,3] 5790 v1 -> [4] 5791 ... 5792 e5 -> [8, 9] 5793 .ve 5794 5795 which corresponds to the dofs 5796 .vb 5797 6 10 11 7 5798 13 2 3 15 5799 12 0 1 14 5800 4 8 9 5 5801 .ve 5802 5803 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5804 .vb 5805 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5806 .ve 5807 5808 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5809 .vb 5810 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5811 .ve 5812 5813 Level: developer 5814 5815 Notes: 5816 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5817 degree of the basis. 5818 5819 This is required to run with libCEED. 5820 5821 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5822 @*/ 5823 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5824 { 5825 DMLabel label; 5826 PetscInt dim, depth = -1, eStart = -1, Nf; 5827 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5828 5829 PetscFunctionBegin; 5830 PetscCall(DMGetDimension(dm, &dim)); 5831 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5832 if (point < 0) { 5833 PetscInt sStart, sEnd; 5834 5835 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5836 point = sEnd - sStart ? sStart : point; 5837 } 5838 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5839 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5840 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5841 if (depth == 1) { 5842 eStart = point; 5843 } else if (depth == dim) { 5844 const PetscInt *cone; 5845 5846 PetscCall(DMPlexGetCone(dm, point, &cone)); 5847 if (dim == 2) eStart = cone[0]; 5848 else if (dim == 3) { 5849 const PetscInt *cone2; 5850 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5851 eStart = cone2[0]; 5852 } 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); 5853 } 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); 5854 5855 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5856 for (PetscInt d = 1; d <= dim; d++) { 5857 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5858 PetscInt *perm; 5859 5860 for (f = 0; f < Nf; ++f) { 5861 PetscInt dof; 5862 5863 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5864 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5865 if (!continuous && d < dim) continue; 5866 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5867 size += dof * Nc; 5868 } 5869 PetscCall(PetscMalloc1(size, &perm)); 5870 for (f = 0; f < Nf; ++f) { 5871 switch (d) { 5872 case 1: 5873 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5874 if (!continuous && d < dim) continue; 5875 /* 5876 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5877 We want [ vtx0; edge of length k-1; vtx1 ] 5878 */ 5879 if (continuous) { 5880 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5881 for (i = 0; i < k - 1; i++) 5882 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5883 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5884 foffset = offset; 5885 } else { 5886 PetscInt dof; 5887 5888 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5889 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5890 foffset = offset; 5891 } 5892 break; 5893 case 2: 5894 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5895 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5896 if (!continuous && d < dim) continue; 5897 /* The SEM order is 5898 5899 v_lb, {e_b}, v_rb, 5900 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5901 v_lt, reverse {e_t}, v_rt 5902 */ 5903 if (continuous) { 5904 const PetscInt of = 0; 5905 const PetscInt oeb = of + PetscSqr(k - 1); 5906 const PetscInt oer = oeb + (k - 1); 5907 const PetscInt oet = oer + (k - 1); 5908 const PetscInt oel = oet + (k - 1); 5909 const PetscInt ovlb = oel + (k - 1); 5910 const PetscInt ovrb = ovlb + 1; 5911 const PetscInt ovrt = ovrb + 1; 5912 const PetscInt ovlt = ovrt + 1; 5913 PetscInt o; 5914 5915 /* bottom */ 5916 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5917 for (o = oeb; o < oer; ++o) 5918 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5919 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5920 /* middle */ 5921 for (i = 0; i < k - 1; ++i) { 5922 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5923 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5924 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5925 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5926 } 5927 /* top */ 5928 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5929 for (o = oel - 1; o >= oet; --o) 5930 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5931 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5932 foffset = offset; 5933 } else { 5934 PetscInt dof; 5935 5936 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5937 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5938 foffset = offset; 5939 } 5940 break; 5941 case 3: 5942 /* The original hex closure is 5943 5944 {c, 5945 f_b, f_t, f_f, f_b, f_r, f_l, 5946 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5947 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5948 */ 5949 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5950 if (!continuous && d < dim) continue; 5951 /* The SEM order is 5952 Bottom Slice 5953 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5954 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5955 v_blb, {e_bb}, v_brb, 5956 5957 Middle Slice (j) 5958 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5959 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5960 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5961 5962 Top Slice 5963 v_tlf, {e_tf}, v_trf, 5964 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5965 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5966 */ 5967 if (continuous) { 5968 const PetscInt oc = 0; 5969 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5970 const PetscInt oft = ofb + PetscSqr(k - 1); 5971 const PetscInt off = oft + PetscSqr(k - 1); 5972 const PetscInt ofk = off + PetscSqr(k - 1); 5973 const PetscInt ofr = ofk + PetscSqr(k - 1); 5974 const PetscInt ofl = ofr + PetscSqr(k - 1); 5975 const PetscInt oebl = ofl + PetscSqr(k - 1); 5976 const PetscInt oebb = oebl + (k - 1); 5977 const PetscInt oebr = oebb + (k - 1); 5978 const PetscInt oebf = oebr + (k - 1); 5979 const PetscInt oetf = oebf + (k - 1); 5980 const PetscInt oetr = oetf + (k - 1); 5981 const PetscInt oetb = oetr + (k - 1); 5982 const PetscInt oetl = oetb + (k - 1); 5983 const PetscInt oerf = oetl + (k - 1); 5984 const PetscInt oelf = oerf + (k - 1); 5985 const PetscInt oelb = oelf + (k - 1); 5986 const PetscInt oerb = oelb + (k - 1); 5987 const PetscInt ovblf = oerb + (k - 1); 5988 const PetscInt ovblb = ovblf + 1; 5989 const PetscInt ovbrb = ovblb + 1; 5990 const PetscInt ovbrf = ovbrb + 1; 5991 const PetscInt ovtlf = ovbrf + 1; 5992 const PetscInt ovtrf = ovtlf + 1; 5993 const PetscInt ovtrb = ovtrf + 1; 5994 const PetscInt ovtlb = ovtrb + 1; 5995 PetscInt o, n; 5996 5997 /* Bottom Slice */ 5998 /* bottom */ 5999 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6000 for (o = oetf - 1; o >= oebf; --o) 6001 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6002 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6003 /* middle */ 6004 for (i = 0; i < k - 1; ++i) { 6005 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6006 for (n = 0; n < k - 1; ++n) { 6007 o = ofb + n * (k - 1) + i; 6008 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6009 } 6010 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6011 } 6012 /* top */ 6013 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6014 for (o = oebb; o < oebr; ++o) 6015 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6016 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6017 6018 /* Middle Slice */ 6019 for (j = 0; j < k - 1; ++j) { 6020 /* bottom */ 6021 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6022 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6023 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6024 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6025 /* middle */ 6026 for (i = 0; i < k - 1; ++i) { 6027 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6028 for (n = 0; n < k - 1; ++n) 6029 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6030 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6031 } 6032 /* top */ 6033 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6034 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6035 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6036 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6037 } 6038 6039 /* Top Slice */ 6040 /* bottom */ 6041 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6042 for (o = oetf; o < oetr; ++o) 6043 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6044 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6045 /* middle */ 6046 for (i = 0; i < k - 1; ++i) { 6047 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6048 for (n = 0; n < k - 1; ++n) 6049 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6050 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6051 } 6052 /* top */ 6053 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6054 for (o = oetl - 1; o >= oetb; --o) 6055 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6056 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6057 6058 foffset = offset; 6059 } else { 6060 PetscInt dof; 6061 6062 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6063 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6064 foffset = offset; 6065 } 6066 break; 6067 default: 6068 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6069 } 6070 } 6071 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6072 /* Check permutation */ 6073 { 6074 PetscInt *check; 6075 6076 PetscCall(PetscMalloc1(size, &check)); 6077 for (i = 0; i < size; ++i) { 6078 check[i] = -1; 6079 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6080 } 6081 for (i = 0; i < size; ++i) check[perm[i]] = i; 6082 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6083 PetscCall(PetscFree(check)); 6084 } 6085 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6086 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6087 PetscInt *loc_perm; 6088 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6089 for (PetscInt i = 0; i < size; i++) { 6090 loc_perm[i] = perm[i]; 6091 loc_perm[size + i] = size + perm[i]; 6092 } 6093 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6094 } 6095 } 6096 PetscFunctionReturn(PETSC_SUCCESS); 6097 } 6098 6099 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6100 { 6101 PetscDS prob; 6102 PetscInt depth, Nf, h; 6103 DMLabel label; 6104 6105 PetscFunctionBeginHot; 6106 PetscCall(DMGetDS(dm, &prob)); 6107 Nf = prob->Nf; 6108 label = dm->depthLabel; 6109 *dspace = NULL; 6110 if (field < Nf) { 6111 PetscObject disc = prob->disc[field]; 6112 6113 if (disc->classid == PETSCFE_CLASSID) { 6114 PetscDualSpace dsp; 6115 6116 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6117 PetscCall(DMLabelGetNumValues(label, &depth)); 6118 PetscCall(DMLabelGetValue(label, point, &h)); 6119 h = depth - 1 - h; 6120 if (h) { 6121 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6122 } else { 6123 *dspace = dsp; 6124 } 6125 } 6126 } 6127 PetscFunctionReturn(PETSC_SUCCESS); 6128 } 6129 6130 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6131 { 6132 PetscScalar *array; 6133 const PetscScalar *vArray; 6134 const PetscInt *cone, *coneO; 6135 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6136 6137 PetscFunctionBeginHot; 6138 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6139 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6140 PetscCall(DMPlexGetCone(dm, point, &cone)); 6141 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6142 if (!values || !*values) { 6143 if ((point >= pStart) && (point < pEnd)) { 6144 PetscInt dof; 6145 6146 PetscCall(PetscSectionGetDof(section, point, &dof)); 6147 size += dof; 6148 } 6149 for (p = 0; p < numPoints; ++p) { 6150 const PetscInt cp = cone[p]; 6151 PetscInt dof; 6152 6153 if ((cp < pStart) || (cp >= pEnd)) continue; 6154 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6155 size += dof; 6156 } 6157 if (!values) { 6158 if (csize) *csize = size; 6159 PetscFunctionReturn(PETSC_SUCCESS); 6160 } 6161 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6162 } else { 6163 array = *values; 6164 } 6165 size = 0; 6166 PetscCall(VecGetArrayRead(v, &vArray)); 6167 if ((point >= pStart) && (point < pEnd)) { 6168 PetscInt dof, off, d; 6169 const PetscScalar *varr; 6170 6171 PetscCall(PetscSectionGetDof(section, point, &dof)); 6172 PetscCall(PetscSectionGetOffset(section, point, &off)); 6173 varr = PetscSafePointerPlusOffset(vArray, off); 6174 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6175 size += dof; 6176 } 6177 for (p = 0; p < numPoints; ++p) { 6178 const PetscInt cp = cone[p]; 6179 PetscInt o = coneO[p]; 6180 PetscInt dof, off, d; 6181 const PetscScalar *varr; 6182 6183 if ((cp < pStart) || (cp >= pEnd)) continue; 6184 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6185 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6186 varr = PetscSafePointerPlusOffset(vArray, off); 6187 if (o >= 0) { 6188 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6189 } else { 6190 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6191 } 6192 size += dof; 6193 } 6194 PetscCall(VecRestoreArrayRead(v, &vArray)); 6195 if (!*values) { 6196 if (csize) *csize = size; 6197 *values = array; 6198 } else { 6199 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6200 *csize = size; 6201 } 6202 PetscFunctionReturn(PETSC_SUCCESS); 6203 } 6204 6205 /* Compress out points not in the section */ 6206 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6207 { 6208 const PetscInt np = *numPoints; 6209 PetscInt pStart, pEnd, p, q; 6210 6211 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6212 for (p = 0, q = 0; p < np; ++p) { 6213 const PetscInt r = points[p * 2]; 6214 if ((r >= pStart) && (r < pEnd)) { 6215 points[q * 2] = r; 6216 points[q * 2 + 1] = points[p * 2 + 1]; 6217 ++q; 6218 } 6219 } 6220 *numPoints = q; 6221 return PETSC_SUCCESS; 6222 } 6223 6224 /* Compressed closure does not apply closure permutation */ 6225 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6226 { 6227 const PetscInt *cla = NULL; 6228 PetscInt np, *pts = NULL; 6229 6230 PetscFunctionBeginHot; 6231 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6232 if (!ornt && *clPoints) { 6233 PetscInt dof, off; 6234 6235 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6236 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6237 PetscCall(ISGetIndices(*clPoints, &cla)); 6238 np = dof / 2; 6239 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6240 } else { 6241 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6242 PetscCall(CompressPoints_Private(section, &np, pts)); 6243 } 6244 *numPoints = np; 6245 *points = pts; 6246 *clp = cla; 6247 PetscFunctionReturn(PETSC_SUCCESS); 6248 } 6249 6250 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6251 { 6252 PetscFunctionBeginHot; 6253 if (!*clPoints) { 6254 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6255 } else { 6256 PetscCall(ISRestoreIndices(*clPoints, clp)); 6257 } 6258 *numPoints = 0; 6259 *points = NULL; 6260 *clSec = NULL; 6261 *clPoints = NULL; 6262 *clp = NULL; 6263 PetscFunctionReturn(PETSC_SUCCESS); 6264 } 6265 6266 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6267 { 6268 PetscInt offset = 0, p; 6269 const PetscInt **perms = NULL; 6270 const PetscScalar **flips = NULL; 6271 6272 PetscFunctionBeginHot; 6273 *size = 0; 6274 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6275 for (p = 0; p < numPoints; p++) { 6276 const PetscInt point = points[2 * p]; 6277 const PetscInt *perm = perms ? perms[p] : NULL; 6278 const PetscScalar *flip = flips ? flips[p] : NULL; 6279 PetscInt dof, off, d; 6280 const PetscScalar *varr; 6281 6282 PetscCall(PetscSectionGetDof(section, point, &dof)); 6283 PetscCall(PetscSectionGetOffset(section, point, &off)); 6284 varr = PetscSafePointerPlusOffset(vArray, off); 6285 if (clperm) { 6286 if (perm) { 6287 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6288 } else { 6289 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6290 } 6291 if (flip) { 6292 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6293 } 6294 } else { 6295 if (perm) { 6296 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6297 } else { 6298 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6299 } 6300 if (flip) { 6301 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6302 } 6303 } 6304 offset += dof; 6305 } 6306 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6307 *size = offset; 6308 PetscFunctionReturn(PETSC_SUCCESS); 6309 } 6310 6311 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[]) 6312 { 6313 PetscInt offset = 0, f; 6314 6315 PetscFunctionBeginHot; 6316 *size = 0; 6317 for (f = 0; f < numFields; ++f) { 6318 PetscInt p; 6319 const PetscInt **perms = NULL; 6320 const PetscScalar **flips = NULL; 6321 6322 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6323 for (p = 0; p < numPoints; p++) { 6324 const PetscInt point = points[2 * p]; 6325 PetscInt fdof, foff, b; 6326 const PetscScalar *varr; 6327 const PetscInt *perm = perms ? perms[p] : NULL; 6328 const PetscScalar *flip = flips ? flips[p] : NULL; 6329 6330 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6331 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6332 varr = &vArray[foff]; 6333 if (clperm) { 6334 if (perm) { 6335 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6336 } else { 6337 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6338 } 6339 if (flip) { 6340 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6341 } 6342 } else { 6343 if (perm) { 6344 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6345 } else { 6346 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6347 } 6348 if (flip) { 6349 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6350 } 6351 } 6352 offset += fdof; 6353 } 6354 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6355 } 6356 *size = offset; 6357 PetscFunctionReturn(PETSC_SUCCESS); 6358 } 6359 6360 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6361 { 6362 PetscSection clSection; 6363 IS clPoints; 6364 PetscInt *points = NULL; 6365 const PetscInt *clp, *perm = NULL; 6366 PetscInt depth, numFields, numPoints, asize; 6367 6368 PetscFunctionBeginHot; 6369 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6370 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6371 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6372 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6373 PetscCall(DMPlexGetDepth(dm, &depth)); 6374 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6375 if (depth == 1 && numFields < 2) { 6376 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6377 PetscFunctionReturn(PETSC_SUCCESS); 6378 } 6379 /* Get points */ 6380 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6381 /* Get sizes */ 6382 asize = 0; 6383 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6384 PetscInt dof; 6385 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6386 asize += dof; 6387 } 6388 if (values) { 6389 const PetscScalar *vArray; 6390 PetscInt size; 6391 6392 if (*values) { 6393 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); 6394 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6395 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6396 PetscCall(VecGetArrayRead(v, &vArray)); 6397 /* Get values */ 6398 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6399 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6400 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6401 /* Cleanup array */ 6402 PetscCall(VecRestoreArrayRead(v, &vArray)); 6403 } 6404 if (csize) *csize = asize; 6405 /* Cleanup points */ 6406 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6407 PetscFunctionReturn(PETSC_SUCCESS); 6408 } 6409 6410 /*@C 6411 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6412 6413 Not collective 6414 6415 Input Parameters: 6416 + dm - The `DM` 6417 . section - The section describing the layout in `v`, or `NULL` to use the default section 6418 . v - The local vector 6419 - point - The point in the `DM` 6420 6421 Input/Output Parameters: 6422 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6423 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6424 if the user provided `NULL`, it is a borrowed array and should not be freed 6425 6426 Level: intermediate 6427 6428 Notes: 6429 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6430 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6431 assembly function, and a user may already have allocated storage for this operation. 6432 6433 A typical use could be 6434 .vb 6435 values = NULL; 6436 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6437 for (cl = 0; cl < clSize; ++cl) { 6438 <Compute on closure> 6439 } 6440 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6441 .ve 6442 or 6443 .vb 6444 PetscMalloc1(clMaxSize, &values); 6445 for (p = pStart; p < pEnd; ++p) { 6446 clSize = clMaxSize; 6447 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6448 for (cl = 0; cl < clSize; ++cl) { 6449 <Compute on closure> 6450 } 6451 } 6452 PetscFree(values); 6453 .ve 6454 6455 Fortran Notes: 6456 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6457 6458 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6459 @*/ 6460 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6461 { 6462 PetscFunctionBeginHot; 6463 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6464 PetscFunctionReturn(PETSC_SUCCESS); 6465 } 6466 6467 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6468 { 6469 DMLabel depthLabel; 6470 PetscSection clSection; 6471 IS clPoints; 6472 PetscScalar *array; 6473 const PetscScalar *vArray; 6474 PetscInt *points = NULL; 6475 const PetscInt *clp, *perm = NULL; 6476 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6477 6478 PetscFunctionBeginHot; 6479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6480 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6481 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6482 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6483 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6484 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6485 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6486 if (mdepth == 1 && numFields < 2) { 6487 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6488 PetscFunctionReturn(PETSC_SUCCESS); 6489 } 6490 /* Get points */ 6491 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6492 for (clsize = 0, p = 0; p < Np; p++) { 6493 PetscInt dof; 6494 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6495 clsize += dof; 6496 } 6497 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6498 /* Filter points */ 6499 for (p = 0; p < numPoints * 2; p += 2) { 6500 PetscInt dep; 6501 6502 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6503 if (dep != depth) continue; 6504 points[Np * 2 + 0] = points[p]; 6505 points[Np * 2 + 1] = points[p + 1]; 6506 ++Np; 6507 } 6508 /* Get array */ 6509 if (!values || !*values) { 6510 PetscInt asize = 0, dof; 6511 6512 for (p = 0; p < Np * 2; p += 2) { 6513 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6514 asize += dof; 6515 } 6516 if (!values) { 6517 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6518 if (csize) *csize = asize; 6519 PetscFunctionReturn(PETSC_SUCCESS); 6520 } 6521 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6522 } else { 6523 array = *values; 6524 } 6525 PetscCall(VecGetArrayRead(v, &vArray)); 6526 /* Get values */ 6527 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6528 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6529 /* Cleanup points */ 6530 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6531 /* Cleanup array */ 6532 PetscCall(VecRestoreArrayRead(v, &vArray)); 6533 if (!*values) { 6534 if (csize) *csize = size; 6535 *values = array; 6536 } else { 6537 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6538 *csize = size; 6539 } 6540 PetscFunctionReturn(PETSC_SUCCESS); 6541 } 6542 6543 /*@C 6544 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6545 6546 Not collective 6547 6548 Input Parameters: 6549 + dm - The `DM` 6550 . section - The section describing the layout in `v`, or `NULL` to use the default section 6551 . v - The local vector 6552 . point - The point in the `DM` 6553 . csize - The number of values in the closure, or `NULL` 6554 - values - The array of values, which is a borrowed array and should not be freed 6555 6556 Level: intermediate 6557 6558 Note: 6559 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6560 6561 Fortran Notes: 6562 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6563 6564 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6565 @*/ 6566 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6567 { 6568 PetscInt size = 0; 6569 6570 PetscFunctionBegin; 6571 /* Should work without recalculating size */ 6572 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6573 *values = NULL; 6574 PetscFunctionReturn(PETSC_SUCCESS); 6575 } 6576 6577 static inline void add(PetscScalar *x, PetscScalar y) 6578 { 6579 *x += y; 6580 } 6581 static inline void insert(PetscScalar *x, PetscScalar y) 6582 { 6583 *x = y; 6584 } 6585 6586 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[]) 6587 { 6588 PetscInt cdof; /* The number of constraints on this point */ 6589 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6590 PetscScalar *a; 6591 PetscInt off, cind = 0, k; 6592 6593 PetscFunctionBegin; 6594 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6595 PetscCall(PetscSectionGetOffset(section, point, &off)); 6596 a = &array[off]; 6597 if (!cdof || setBC) { 6598 if (clperm) { 6599 if (perm) { 6600 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6601 } else { 6602 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6603 } 6604 } else { 6605 if (perm) { 6606 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6607 } else { 6608 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6609 } 6610 } 6611 } else { 6612 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6613 if (clperm) { 6614 if (perm) { 6615 for (k = 0; k < dof; ++k) { 6616 if ((cind < cdof) && (k == cdofs[cind])) { 6617 ++cind; 6618 continue; 6619 } 6620 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6621 } 6622 } else { 6623 for (k = 0; k < dof; ++k) { 6624 if ((cind < cdof) && (k == cdofs[cind])) { 6625 ++cind; 6626 continue; 6627 } 6628 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6629 } 6630 } 6631 } else { 6632 if (perm) { 6633 for (k = 0; k < dof; ++k) { 6634 if ((cind < cdof) && (k == cdofs[cind])) { 6635 ++cind; 6636 continue; 6637 } 6638 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6639 } 6640 } else { 6641 for (k = 0; k < dof; ++k) { 6642 if ((cind < cdof) && (k == cdofs[cind])) { 6643 ++cind; 6644 continue; 6645 } 6646 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6647 } 6648 } 6649 } 6650 } 6651 PetscFunctionReturn(PETSC_SUCCESS); 6652 } 6653 6654 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[]) 6655 { 6656 PetscInt cdof; /* The number of constraints on this point */ 6657 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6658 PetscScalar *a; 6659 PetscInt off, cind = 0, k; 6660 6661 PetscFunctionBegin; 6662 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6663 PetscCall(PetscSectionGetOffset(section, point, &off)); 6664 a = &array[off]; 6665 if (cdof) { 6666 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6667 if (clperm) { 6668 if (perm) { 6669 for (k = 0; k < dof; ++k) { 6670 if ((cind < cdof) && (k == cdofs[cind])) { 6671 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6672 cind++; 6673 } 6674 } 6675 } else { 6676 for (k = 0; k < dof; ++k) { 6677 if ((cind < cdof) && (k == cdofs[cind])) { 6678 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6679 cind++; 6680 } 6681 } 6682 } 6683 } else { 6684 if (perm) { 6685 for (k = 0; k < dof; ++k) { 6686 if ((cind < cdof) && (k == cdofs[cind])) { 6687 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6688 cind++; 6689 } 6690 } 6691 } else { 6692 for (k = 0; k < dof; ++k) { 6693 if ((cind < cdof) && (k == cdofs[cind])) { 6694 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6695 cind++; 6696 } 6697 } 6698 } 6699 } 6700 } 6701 PetscFunctionReturn(PETSC_SUCCESS); 6702 } 6703 6704 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[]) 6705 { 6706 PetscScalar *a; 6707 PetscInt fdof, foff, fcdof, foffset = *offset; 6708 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6709 PetscInt cind = 0, b; 6710 6711 PetscFunctionBegin; 6712 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6713 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6714 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6715 a = &array[foff]; 6716 if (!fcdof || setBC) { 6717 if (clperm) { 6718 if (perm) { 6719 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6720 } else { 6721 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6722 } 6723 } else { 6724 if (perm) { 6725 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6726 } else { 6727 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6728 } 6729 } 6730 } else { 6731 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6732 if (clperm) { 6733 if (perm) { 6734 for (b = 0; b < fdof; b++) { 6735 if ((cind < fcdof) && (b == fcdofs[cind])) { 6736 ++cind; 6737 continue; 6738 } 6739 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6740 } 6741 } else { 6742 for (b = 0; b < fdof; b++) { 6743 if ((cind < fcdof) && (b == fcdofs[cind])) { 6744 ++cind; 6745 continue; 6746 } 6747 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6748 } 6749 } 6750 } else { 6751 if (perm) { 6752 for (b = 0; b < fdof; b++) { 6753 if ((cind < fcdof) && (b == fcdofs[cind])) { 6754 ++cind; 6755 continue; 6756 } 6757 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6758 } 6759 } else { 6760 for (b = 0; b < fdof; b++) { 6761 if ((cind < fcdof) && (b == fcdofs[cind])) { 6762 ++cind; 6763 continue; 6764 } 6765 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6766 } 6767 } 6768 } 6769 } 6770 *offset += fdof; 6771 PetscFunctionReturn(PETSC_SUCCESS); 6772 } 6773 6774 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[]) 6775 { 6776 PetscScalar *a; 6777 PetscInt fdof, foff, fcdof, foffset = *offset; 6778 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6779 PetscInt Nc, cind = 0, ncind = 0, b; 6780 PetscBool ncSet, fcSet; 6781 6782 PetscFunctionBegin; 6783 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6784 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6785 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6786 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6787 a = &array[foff]; 6788 if (fcdof) { 6789 /* We just override fcdof and fcdofs with Ncc and comps */ 6790 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6791 if (clperm) { 6792 if (perm) { 6793 if (comps) { 6794 for (b = 0; b < fdof; b++) { 6795 ncSet = fcSet = PETSC_FALSE; 6796 if (b % Nc == comps[ncind]) { 6797 ncind = (ncind + 1) % Ncc; 6798 ncSet = PETSC_TRUE; 6799 } 6800 if ((cind < fcdof) && (b == fcdofs[cind])) { 6801 ++cind; 6802 fcSet = PETSC_TRUE; 6803 } 6804 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6805 } 6806 } else { 6807 for (b = 0; b < fdof; b++) { 6808 if ((cind < fcdof) && (b == fcdofs[cind])) { 6809 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6810 ++cind; 6811 } 6812 } 6813 } 6814 } else { 6815 if (comps) { 6816 for (b = 0; b < fdof; b++) { 6817 ncSet = fcSet = PETSC_FALSE; 6818 if (b % Nc == comps[ncind]) { 6819 ncind = (ncind + 1) % Ncc; 6820 ncSet = PETSC_TRUE; 6821 } 6822 if ((cind < fcdof) && (b == fcdofs[cind])) { 6823 ++cind; 6824 fcSet = PETSC_TRUE; 6825 } 6826 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6827 } 6828 } else { 6829 for (b = 0; b < fdof; b++) { 6830 if ((cind < fcdof) && (b == fcdofs[cind])) { 6831 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6832 ++cind; 6833 } 6834 } 6835 } 6836 } 6837 } else { 6838 if (perm) { 6839 if (comps) { 6840 for (b = 0; b < fdof; b++) { 6841 ncSet = fcSet = PETSC_FALSE; 6842 if (b % Nc == comps[ncind]) { 6843 ncind = (ncind + 1) % Ncc; 6844 ncSet = PETSC_TRUE; 6845 } 6846 if ((cind < fcdof) && (b == fcdofs[cind])) { 6847 ++cind; 6848 fcSet = PETSC_TRUE; 6849 } 6850 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6851 } 6852 } else { 6853 for (b = 0; b < fdof; b++) { 6854 if ((cind < fcdof) && (b == fcdofs[cind])) { 6855 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6856 ++cind; 6857 } 6858 } 6859 } 6860 } else { 6861 if (comps) { 6862 for (b = 0; b < fdof; b++) { 6863 ncSet = fcSet = PETSC_FALSE; 6864 if (b % Nc == comps[ncind]) { 6865 ncind = (ncind + 1) % Ncc; 6866 ncSet = PETSC_TRUE; 6867 } 6868 if ((cind < fcdof) && (b == fcdofs[cind])) { 6869 ++cind; 6870 fcSet = PETSC_TRUE; 6871 } 6872 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6873 } 6874 } else { 6875 for (b = 0; b < fdof; b++) { 6876 if ((cind < fcdof) && (b == fcdofs[cind])) { 6877 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6878 ++cind; 6879 } 6880 } 6881 } 6882 } 6883 } 6884 } 6885 *offset += fdof; 6886 PetscFunctionReturn(PETSC_SUCCESS); 6887 } 6888 6889 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6890 { 6891 PetscScalar *array; 6892 const PetscInt *cone, *coneO; 6893 PetscInt pStart, pEnd, p, numPoints, off, dof; 6894 6895 PetscFunctionBeginHot; 6896 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6897 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6898 PetscCall(DMPlexGetCone(dm, point, &cone)); 6899 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6900 PetscCall(VecGetArray(v, &array)); 6901 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6902 const PetscInt cp = !p ? point : cone[p - 1]; 6903 const PetscInt o = !p ? 0 : coneO[p - 1]; 6904 6905 if ((cp < pStart) || (cp >= pEnd)) { 6906 dof = 0; 6907 continue; 6908 } 6909 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6910 /* ADD_VALUES */ 6911 { 6912 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6913 PetscScalar *a; 6914 PetscInt cdof, coff, cind = 0, k; 6915 6916 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6917 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6918 a = &array[coff]; 6919 if (!cdof) { 6920 if (o >= 0) { 6921 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6922 } else { 6923 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6924 } 6925 } else { 6926 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6927 if (o >= 0) { 6928 for (k = 0; k < dof; ++k) { 6929 if ((cind < cdof) && (k == cdofs[cind])) { 6930 ++cind; 6931 continue; 6932 } 6933 a[k] += values[off + k]; 6934 } 6935 } else { 6936 for (k = 0; k < dof; ++k) { 6937 if ((cind < cdof) && (k == cdofs[cind])) { 6938 ++cind; 6939 continue; 6940 } 6941 a[k] += values[off + dof - k - 1]; 6942 } 6943 } 6944 } 6945 } 6946 } 6947 PetscCall(VecRestoreArray(v, &array)); 6948 PetscFunctionReturn(PETSC_SUCCESS); 6949 } 6950 6951 /*@C 6952 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6953 6954 Not collective 6955 6956 Input Parameters: 6957 + dm - The `DM` 6958 . section - The section describing the layout in `v`, or `NULL` to use the default section 6959 . v - The local vector 6960 . point - The point in the `DM` 6961 . values - The array of values 6962 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6963 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6964 6965 Level: intermediate 6966 6967 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6968 @*/ 6969 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6970 { 6971 PetscSection clSection; 6972 IS clPoints; 6973 PetscScalar *array; 6974 PetscInt *points = NULL; 6975 const PetscInt *clp, *clperm = NULL; 6976 PetscInt depth, numFields, numPoints, p, clsize; 6977 6978 PetscFunctionBeginHot; 6979 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6980 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6981 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6982 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6983 PetscCall(DMPlexGetDepth(dm, &depth)); 6984 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6985 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6986 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6987 PetscFunctionReturn(PETSC_SUCCESS); 6988 } 6989 /* Get points */ 6990 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6991 for (clsize = 0, p = 0; p < numPoints; p++) { 6992 PetscInt dof; 6993 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6994 clsize += dof; 6995 } 6996 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6997 /* Get array */ 6998 PetscCall(VecGetArray(v, &array)); 6999 /* Get values */ 7000 if (numFields > 0) { 7001 PetscInt offset = 0, f; 7002 for (f = 0; f < numFields; ++f) { 7003 const PetscInt **perms = NULL; 7004 const PetscScalar **flips = NULL; 7005 7006 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7007 switch (mode) { 7008 case INSERT_VALUES: 7009 for (p = 0; p < numPoints; p++) { 7010 const PetscInt point = points[2 * p]; 7011 const PetscInt *perm = perms ? perms[p] : NULL; 7012 const PetscScalar *flip = flips ? flips[p] : NULL; 7013 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7014 } 7015 break; 7016 case INSERT_ALL_VALUES: 7017 for (p = 0; p < numPoints; p++) { 7018 const PetscInt point = points[2 * p]; 7019 const PetscInt *perm = perms ? perms[p] : NULL; 7020 const PetscScalar *flip = flips ? flips[p] : NULL; 7021 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7022 } 7023 break; 7024 case INSERT_BC_VALUES: 7025 for (p = 0; p < numPoints; p++) { 7026 const PetscInt point = points[2 * p]; 7027 const PetscInt *perm = perms ? perms[p] : NULL; 7028 const PetscScalar *flip = flips ? flips[p] : NULL; 7029 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7030 } 7031 break; 7032 case ADD_VALUES: 7033 for (p = 0; p < numPoints; p++) { 7034 const PetscInt point = points[2 * p]; 7035 const PetscInt *perm = perms ? perms[p] : NULL; 7036 const PetscScalar *flip = flips ? flips[p] : NULL; 7037 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7038 } 7039 break; 7040 case ADD_ALL_VALUES: 7041 for (p = 0; p < numPoints; p++) { 7042 const PetscInt point = points[2 * p]; 7043 const PetscInt *perm = perms ? perms[p] : NULL; 7044 const PetscScalar *flip = flips ? flips[p] : NULL; 7045 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7046 } 7047 break; 7048 case ADD_BC_VALUES: 7049 for (p = 0; p < numPoints; p++) { 7050 const PetscInt point = points[2 * p]; 7051 const PetscInt *perm = perms ? perms[p] : NULL; 7052 const PetscScalar *flip = flips ? flips[p] : NULL; 7053 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7054 } 7055 break; 7056 default: 7057 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7058 } 7059 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7060 } 7061 } else { 7062 PetscInt dof, off; 7063 const PetscInt **perms = NULL; 7064 const PetscScalar **flips = NULL; 7065 7066 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7067 switch (mode) { 7068 case INSERT_VALUES: 7069 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7070 const PetscInt point = points[2 * p]; 7071 const PetscInt *perm = perms ? perms[p] : NULL; 7072 const PetscScalar *flip = flips ? flips[p] : NULL; 7073 PetscCall(PetscSectionGetDof(section, point, &dof)); 7074 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7075 } 7076 break; 7077 case INSERT_ALL_VALUES: 7078 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7079 const PetscInt point = points[2 * p]; 7080 const PetscInt *perm = perms ? perms[p] : NULL; 7081 const PetscScalar *flip = flips ? flips[p] : NULL; 7082 PetscCall(PetscSectionGetDof(section, point, &dof)); 7083 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7084 } 7085 break; 7086 case INSERT_BC_VALUES: 7087 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7088 const PetscInt point = points[2 * p]; 7089 const PetscInt *perm = perms ? perms[p] : NULL; 7090 const PetscScalar *flip = flips ? flips[p] : NULL; 7091 PetscCall(PetscSectionGetDof(section, point, &dof)); 7092 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7093 } 7094 break; 7095 case ADD_VALUES: 7096 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7097 const PetscInt point = points[2 * p]; 7098 const PetscInt *perm = perms ? perms[p] : NULL; 7099 const PetscScalar *flip = flips ? flips[p] : NULL; 7100 PetscCall(PetscSectionGetDof(section, point, &dof)); 7101 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7102 } 7103 break; 7104 case ADD_ALL_VALUES: 7105 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7106 const PetscInt point = points[2 * p]; 7107 const PetscInt *perm = perms ? perms[p] : NULL; 7108 const PetscScalar *flip = flips ? flips[p] : NULL; 7109 PetscCall(PetscSectionGetDof(section, point, &dof)); 7110 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7111 } 7112 break; 7113 case ADD_BC_VALUES: 7114 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7115 const PetscInt point = points[2 * p]; 7116 const PetscInt *perm = perms ? perms[p] : NULL; 7117 const PetscScalar *flip = flips ? flips[p] : NULL; 7118 PetscCall(PetscSectionGetDof(section, point, &dof)); 7119 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7120 } 7121 break; 7122 default: 7123 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7124 } 7125 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7126 } 7127 /* Cleanup points */ 7128 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7129 /* Cleanup array */ 7130 PetscCall(VecRestoreArray(v, &array)); 7131 PetscFunctionReturn(PETSC_SUCCESS); 7132 } 7133 7134 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7135 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7136 { 7137 PetscFunctionBegin; 7138 *contains = PETSC_TRUE; 7139 if (label) { 7140 PetscInt fdof; 7141 7142 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7143 if (!*contains) { 7144 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7145 *offset += fdof; 7146 PetscFunctionReturn(PETSC_SUCCESS); 7147 } 7148 } 7149 PetscFunctionReturn(PETSC_SUCCESS); 7150 } 7151 7152 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7153 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) 7154 { 7155 PetscSection clSection; 7156 IS clPoints; 7157 PetscScalar *array; 7158 PetscInt *points = NULL; 7159 const PetscInt *clp; 7160 PetscInt numFields, numPoints, p; 7161 PetscInt offset = 0, f; 7162 7163 PetscFunctionBeginHot; 7164 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7165 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7166 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7167 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7168 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7169 /* Get points */ 7170 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7171 /* Get array */ 7172 PetscCall(VecGetArray(v, &array)); 7173 /* Get values */ 7174 for (f = 0; f < numFields; ++f) { 7175 const PetscInt **perms = NULL; 7176 const PetscScalar **flips = NULL; 7177 PetscBool contains; 7178 7179 if (!fieldActive[f]) { 7180 for (p = 0; p < numPoints * 2; p += 2) { 7181 PetscInt fdof; 7182 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7183 offset += fdof; 7184 } 7185 continue; 7186 } 7187 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7188 switch (mode) { 7189 case INSERT_VALUES: 7190 for (p = 0; p < numPoints; p++) { 7191 const PetscInt point = points[2 * p]; 7192 const PetscInt *perm = perms ? perms[p] : NULL; 7193 const PetscScalar *flip = flips ? flips[p] : NULL; 7194 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7195 if (!contains) continue; 7196 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7197 } 7198 break; 7199 case INSERT_ALL_VALUES: 7200 for (p = 0; p < numPoints; p++) { 7201 const PetscInt point = points[2 * p]; 7202 const PetscInt *perm = perms ? perms[p] : NULL; 7203 const PetscScalar *flip = flips ? flips[p] : NULL; 7204 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7205 if (!contains) continue; 7206 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7207 } 7208 break; 7209 case INSERT_BC_VALUES: 7210 for (p = 0; p < numPoints; p++) { 7211 const PetscInt point = points[2 * p]; 7212 const PetscInt *perm = perms ? perms[p] : NULL; 7213 const PetscScalar *flip = flips ? flips[p] : NULL; 7214 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7215 if (!contains) continue; 7216 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7217 } 7218 break; 7219 case ADD_VALUES: 7220 for (p = 0; p < numPoints; p++) { 7221 const PetscInt point = points[2 * p]; 7222 const PetscInt *perm = perms ? perms[p] : NULL; 7223 const PetscScalar *flip = flips ? flips[p] : NULL; 7224 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7225 if (!contains) continue; 7226 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7227 } 7228 break; 7229 case ADD_ALL_VALUES: 7230 for (p = 0; p < numPoints; p++) { 7231 const PetscInt point = points[2 * p]; 7232 const PetscInt *perm = perms ? perms[p] : NULL; 7233 const PetscScalar *flip = flips ? flips[p] : NULL; 7234 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7235 if (!contains) continue; 7236 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7237 } 7238 break; 7239 default: 7240 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7241 } 7242 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7243 } 7244 /* Cleanup points */ 7245 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7246 /* Cleanup array */ 7247 PetscCall(VecRestoreArray(v, &array)); 7248 PetscFunctionReturn(PETSC_SUCCESS); 7249 } 7250 7251 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7252 { 7253 PetscMPIInt rank; 7254 PetscInt i, j; 7255 7256 PetscFunctionBegin; 7257 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7258 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7259 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7260 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7261 numCIndices = numCIndices ? numCIndices : numRIndices; 7262 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7263 for (i = 0; i < numRIndices; i++) { 7264 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7265 for (j = 0; j < numCIndices; j++) { 7266 #if defined(PETSC_USE_COMPLEX) 7267 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7268 #else 7269 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7270 #endif 7271 } 7272 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7273 } 7274 PetscFunctionReturn(PETSC_SUCCESS); 7275 } 7276 7277 /* 7278 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7279 7280 Input Parameters: 7281 + section - The section for this data layout 7282 . islocal - Is the section (and thus indices being requested) local or global? 7283 . point - The point contributing dofs with these indices 7284 . off - The global offset of this point 7285 . loff - The local offset of each field 7286 . setBC - The flag determining whether to include indices of boundary values 7287 . perm - A permutation of the dofs on this point, or NULL 7288 - indperm - A permutation of the entire indices array, or NULL 7289 7290 Output Parameter: 7291 . indices - Indices for dofs on this point 7292 7293 Level: developer 7294 7295 Note: The indices could be local or global, depending on the value of 'off'. 7296 */ 7297 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7298 { 7299 PetscInt dof; /* The number of unknowns on this point */ 7300 PetscInt cdof; /* The number of constraints on this point */ 7301 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7302 PetscInt cind = 0, k; 7303 7304 PetscFunctionBegin; 7305 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7306 PetscCall(PetscSectionGetDof(section, point, &dof)); 7307 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7308 if (!cdof || setBC) { 7309 for (k = 0; k < dof; ++k) { 7310 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7311 const PetscInt ind = indperm ? indperm[preind] : preind; 7312 7313 indices[ind] = off + k; 7314 } 7315 } else { 7316 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7317 for (k = 0; k < dof; ++k) { 7318 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7319 const PetscInt ind = indperm ? indperm[preind] : preind; 7320 7321 if ((cind < cdof) && (k == cdofs[cind])) { 7322 /* Insert check for returning constrained indices */ 7323 indices[ind] = -(off + k + 1); 7324 ++cind; 7325 } else { 7326 indices[ind] = off + k - (islocal ? 0 : cind); 7327 } 7328 } 7329 } 7330 *loff += dof; 7331 PetscFunctionReturn(PETSC_SUCCESS); 7332 } 7333 7334 /* 7335 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7336 7337 Input Parameters: 7338 + section - a section (global or local) 7339 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7340 . point - point within section 7341 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7342 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7343 . setBC - identify constrained (boundary condition) points via involution. 7344 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7345 . permsoff - offset 7346 - indperm - index permutation 7347 7348 Output Parameter: 7349 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7350 . indices - array to hold indices (as defined by section) of each dof associated with point 7351 7352 Notes: 7353 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7354 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7355 in the local vector. 7356 7357 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7358 significant). It is invalid to call with a global section and setBC=true. 7359 7360 Developer Note: 7361 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7362 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7363 offset could be obtained from the section instead of passing it explicitly as we do now. 7364 7365 Example: 7366 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7367 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7368 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7369 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. 7370 7371 Level: developer 7372 */ 7373 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[]) 7374 { 7375 PetscInt numFields, foff, f; 7376 7377 PetscFunctionBegin; 7378 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7379 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7380 for (f = 0, foff = 0; f < numFields; ++f) { 7381 PetscInt fdof, cfdof; 7382 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7383 PetscInt cind = 0, b; 7384 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7385 7386 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7387 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7388 if (!cfdof || setBC) { 7389 for (b = 0; b < fdof; ++b) { 7390 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7391 const PetscInt ind = indperm ? indperm[preind] : preind; 7392 7393 indices[ind] = off + foff + b; 7394 } 7395 } else { 7396 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7397 for (b = 0; b < fdof; ++b) { 7398 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7399 const PetscInt ind = indperm ? indperm[preind] : preind; 7400 7401 if ((cind < cfdof) && (b == fcdofs[cind])) { 7402 indices[ind] = -(off + foff + b + 1); 7403 ++cind; 7404 } else { 7405 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7406 } 7407 } 7408 } 7409 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7410 foffs[f] += fdof; 7411 } 7412 PetscFunctionReturn(PETSC_SUCCESS); 7413 } 7414 7415 /* 7416 This version believes the globalSection offsets for each field, rather than just the point offset 7417 7418 . foffs - The offset into 'indices' for each field, since it is segregated by field 7419 7420 Notes: 7421 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7422 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7423 */ 7424 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7425 { 7426 PetscInt numFields, foff, f; 7427 7428 PetscFunctionBegin; 7429 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7430 for (f = 0; f < numFields; ++f) { 7431 PetscInt fdof, cfdof; 7432 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7433 PetscInt cind = 0, b; 7434 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7435 7436 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7437 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7438 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7439 if (!cfdof) { 7440 for (b = 0; b < fdof; ++b) { 7441 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7442 const PetscInt ind = indperm ? indperm[preind] : preind; 7443 7444 indices[ind] = foff + b; 7445 } 7446 } else { 7447 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7448 for (b = 0; b < fdof; ++b) { 7449 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7450 const PetscInt ind = indperm ? indperm[preind] : preind; 7451 7452 if ((cind < cfdof) && (b == fcdofs[cind])) { 7453 indices[ind] = -(foff + b + 1); 7454 ++cind; 7455 } else { 7456 indices[ind] = foff + b - cind; 7457 } 7458 } 7459 } 7460 foffs[f] += fdof; 7461 } 7462 PetscFunctionReturn(PETSC_SUCCESS); 7463 } 7464 7465 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7466 { 7467 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7468 7469 PetscFunctionBegin; 7470 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7471 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7472 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7473 for (PetscInt p = 0; p < nPoints; p++) { 7474 PetscInt b = pnts[2 * p]; 7475 PetscInt bSecDof = 0, bOff; 7476 PetscInt cSecDof = 0; 7477 PetscSection indices_section; 7478 7479 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7480 if (!bSecDof) continue; 7481 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7482 indices_section = cSecDof > 0 ? cSec : section; 7483 if (numFields) { 7484 PetscInt fStart[32], fEnd[32]; 7485 7486 fStart[0] = 0; 7487 fEnd[0] = 0; 7488 for (PetscInt f = 0; f < numFields; f++) { 7489 PetscInt fDof = 0; 7490 7491 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7492 fStart[f + 1] = fStart[f] + fDof; 7493 fEnd[f + 1] = fStart[f + 1]; 7494 } 7495 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7496 // only apply permutations on one side 7497 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7498 for (PetscInt f = 0; f < numFields; f++) { 7499 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7500 } 7501 } else { 7502 PetscInt bEnd = 0; 7503 7504 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7505 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7506 7507 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7508 } 7509 } 7510 PetscFunctionReturn(PETSC_SUCCESS); 7511 } 7512 7513 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[]) 7514 { 7515 Mat cMat; 7516 PetscSection aSec, cSec; 7517 IS aIS; 7518 PetscInt aStart = -1, aEnd = -1; 7519 PetscInt sStart = -1, sEnd = -1; 7520 PetscInt cStart = -1, cEnd = -1; 7521 const PetscInt *anchors; 7522 PetscInt numFields, f, p; 7523 PetscInt newNumPoints = 0, newNumIndices = 0; 7524 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7525 PetscInt oldOffsets[32]; 7526 PetscInt newOffsets[32]; 7527 PetscInt oldOffsetsCopy[32]; 7528 PetscInt newOffsetsCopy[32]; 7529 PetscScalar *modMat = NULL; 7530 PetscBool anyConstrained = PETSC_FALSE; 7531 7532 PetscFunctionBegin; 7533 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7534 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7535 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7536 7537 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7538 /* if there are point-to-point constraints */ 7539 if (aSec) { 7540 PetscCall(PetscArrayzero(newOffsets, 32)); 7541 PetscCall(PetscArrayzero(oldOffsets, 32)); 7542 PetscCall(ISGetIndices(aIS, &anchors)); 7543 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7544 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7545 /* figure out how many points are going to be in the new element matrix 7546 * (we allow double counting, because it's all just going to be summed 7547 * into the global matrix anyway) */ 7548 for (p = 0; p < 2 * numPoints; p += 2) { 7549 PetscInt b = points[p]; 7550 PetscInt bDof = 0, bSecDof = 0; 7551 7552 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7553 if (!bSecDof) continue; 7554 7555 for (PetscInt f = 0; f < numFields; f++) { 7556 PetscInt fDof = 0; 7557 7558 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7559 oldOffsets[f + 1] += fDof; 7560 } 7561 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7562 if (bDof) { 7563 /* this point is constrained */ 7564 /* it is going to be replaced by its anchors */ 7565 PetscInt bOff, q; 7566 7567 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7568 for (q = 0; q < bDof; q++) { 7569 PetscInt a = anchors[bOff + q]; 7570 PetscInt aDof = 0; 7571 7572 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7573 if (aDof) { 7574 anyConstrained = PETSC_TRUE; 7575 newNumPoints += 1; 7576 } 7577 newNumIndices += aDof; 7578 for (f = 0; f < numFields; ++f) { 7579 PetscInt fDof = 0; 7580 7581 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7582 newOffsets[f + 1] += fDof; 7583 } 7584 } 7585 } else { 7586 /* this point is not constrained */ 7587 newNumPoints++; 7588 newNumIndices += bSecDof; 7589 for (f = 0; f < numFields; ++f) { 7590 PetscInt fDof; 7591 7592 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7593 newOffsets[f + 1] += fDof; 7594 } 7595 } 7596 } 7597 } 7598 if (!anyConstrained) { 7599 if (outNumPoints) *outNumPoints = 0; 7600 if (outNumIndices) *outNumIndices = 0; 7601 if (outPoints) *outPoints = NULL; 7602 if (outMat) *outMat = NULL; 7603 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7604 PetscFunctionReturn(PETSC_SUCCESS); 7605 } 7606 7607 if (outNumPoints) *outNumPoints = newNumPoints; 7608 if (outNumIndices) *outNumIndices = newNumIndices; 7609 7610 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7611 for (f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7612 7613 if (!outPoints && !outMat) { 7614 if (offsets) { 7615 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7616 } 7617 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7618 PetscFunctionReturn(PETSC_SUCCESS); 7619 } 7620 7621 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7622 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7623 7624 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7625 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7626 7627 /* output arrays */ 7628 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7629 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7630 7631 // get the new Points 7632 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7633 PetscInt b = points[2 * p]; 7634 PetscInt bDof = 0, bSecDof = 0, bOff; 7635 7636 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7637 if (!bSecDof) continue; 7638 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7639 if (bDof) { 7640 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7641 for (PetscInt q = 0; q < bDof; q++) { 7642 PetscInt a = anchors[bOff + q], aDof = 0; 7643 7644 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7645 if (aDof) { 7646 newPoints[2 * newP] = a; 7647 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7648 newP++; 7649 } 7650 } 7651 } else { 7652 newPoints[2 * newP] = b; 7653 newPoints[2 * newP + 1] = points[2 * p + 1]; 7654 newP++; 7655 } 7656 } 7657 7658 if (outMat) { 7659 PetscScalar *tmpMat; 7660 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7661 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7662 7663 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7664 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7665 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7666 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7667 7668 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7669 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7670 7671 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7672 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7673 7674 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7675 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7676 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7677 // for each field, insert the anchor modification into modMat 7678 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7679 PetscInt fStart = oldOffsets[f]; 7680 PetscInt fNewStart = newOffsets[f]; 7681 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7682 PetscInt b = points[2 * p]; 7683 PetscInt bDof = 0, bSecDof = 0, bOff; 7684 7685 if (b >= sStart && b < sEnd) { 7686 if (numFields) { 7687 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7688 } else { 7689 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7690 } 7691 } 7692 if (!bSecDof) continue; 7693 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7694 if (bDof) { 7695 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7696 for (PetscInt q = 0; q < bDof; q++, newP++) { 7697 PetscInt a = anchors[bOff + q], aDof = 0; 7698 7699 if (a >= sStart && a < sEnd) { 7700 if (numFields) { 7701 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7702 } else { 7703 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7704 } 7705 } 7706 if (aDof) { 7707 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7708 for (PetscInt d = 0; d < bSecDof; d++) { 7709 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7710 } 7711 } 7712 oNew += aDof; 7713 } 7714 } else { 7715 // Insert the identity matrix in this block 7716 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7717 oNew += bSecDof; 7718 newP++; 7719 } 7720 o += bSecDof; 7721 } 7722 } 7723 7724 *outMat = modMat; 7725 7726 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7727 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7728 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7729 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7730 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7731 } 7732 PetscCall(ISRestoreIndices(aIS, &anchors)); 7733 7734 /* output */ 7735 if (outPoints) { 7736 *outPoints = newPoints; 7737 } else { 7738 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7739 } 7740 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7741 PetscFunctionReturn(PETSC_SUCCESS); 7742 } 7743 7744 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) 7745 { 7746 PetscScalar *modMat = NULL; 7747 PetscInt newNumIndices = -1; 7748 7749 PetscFunctionBegin; 7750 /* 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. 7751 modMat is that matrix C */ 7752 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7753 if (outNumIndices) *outNumIndices = newNumIndices; 7754 if (modMat) { 7755 const PetscScalar *newValues = values; 7756 7757 if (multiplyRight) { 7758 PetscScalar *newNewValues = NULL; 7759 PetscBLASInt M = newNumIndices; 7760 PetscBLASInt N = numRows; 7761 PetscBLASInt K = numIndices; 7762 PetscScalar a = 1.0, b = 0.0; 7763 7764 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); 7765 7766 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7767 // row-major to column-major conversion, right multiplication becomes left multiplication 7768 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7769 7770 numCols = newNumIndices; 7771 newValues = newNewValues; 7772 } 7773 7774 if (multiplyLeft) { 7775 PetscScalar *newNewValues = NULL; 7776 PetscBLASInt M = numCols; 7777 PetscBLASInt N = newNumIndices; 7778 PetscBLASInt K = numIndices; 7779 PetscScalar a = 1.0, b = 0.0; 7780 7781 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); 7782 7783 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7784 // row-major to column-major conversion, left multiplication becomes right multiplication 7785 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7786 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7787 newValues = newNewValues; 7788 } 7789 *outValues = (PetscScalar *)newValues; 7790 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7791 } 7792 PetscFunctionReturn(PETSC_SUCCESS); 7793 } 7794 7795 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) 7796 { 7797 PetscFunctionBegin; 7798 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7799 PetscFunctionReturn(PETSC_SUCCESS); 7800 } 7801 7802 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7803 { 7804 /* Closure ordering */ 7805 PetscSection clSection; 7806 IS clPoints; 7807 const PetscInt *clp; 7808 PetscInt *points; 7809 PetscInt Ncl, Ni = 0; 7810 7811 PetscFunctionBeginHot; 7812 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7813 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7814 PetscInt dof; 7815 7816 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7817 Ni += dof; 7818 } 7819 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7820 *closureSize = Ni; 7821 PetscFunctionReturn(PETSC_SUCCESS); 7822 } 7823 7824 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) 7825 { 7826 /* Closure ordering */ 7827 PetscSection clSection; 7828 IS clPoints; 7829 const PetscInt *clp; 7830 PetscInt *points; 7831 const PetscInt *clperm = NULL; 7832 /* Dof permutation and sign flips */ 7833 const PetscInt **perms[32] = {NULL}; 7834 const PetscScalar **flips[32] = {NULL}; 7835 PetscScalar *valCopy = NULL; 7836 /* Hanging node constraints */ 7837 PetscInt *pointsC = NULL; 7838 PetscScalar *valuesC = NULL; 7839 PetscInt NclC, NiC; 7840 7841 PetscInt *idx; 7842 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7843 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7844 PetscInt idxStart, idxEnd; 7845 PetscInt nRows, nCols; 7846 7847 PetscFunctionBeginHot; 7848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7849 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7850 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7851 PetscAssertPointer(numRows, 6); 7852 PetscAssertPointer(numCols, 7); 7853 if (indices) PetscAssertPointer(indices, 8); 7854 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7855 if (values) PetscAssertPointer(values, 10); 7856 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7857 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7858 PetscCall(PetscArrayzero(offsets, 32)); 7859 /* 1) Get points in closure */ 7860 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7861 if (useClPerm) { 7862 PetscInt depth, clsize; 7863 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7864 for (clsize = 0, p = 0; p < Ncl; p++) { 7865 PetscInt dof; 7866 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7867 clsize += dof; 7868 } 7869 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7870 } 7871 /* 2) Get number of indices on these points and field offsets from section */ 7872 for (p = 0; p < Ncl * 2; p += 2) { 7873 PetscInt dof, fdof; 7874 7875 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7876 for (f = 0; f < Nf; ++f) { 7877 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7878 offsets[f + 1] += fdof; 7879 } 7880 Ni += dof; 7881 } 7882 if (*numRows == -1) *numRows = Ni; 7883 if (*numCols == -1) *numCols = Ni; 7884 nRows = *numRows; 7885 nCols = *numCols; 7886 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7887 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7888 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7889 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7890 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7891 for (f = 0; f < PetscMax(1, Nf); ++f) { 7892 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7893 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7894 /* may need to apply sign changes to the element matrix */ 7895 if (values && flips[f]) { 7896 PetscInt foffset = offsets[f]; 7897 7898 for (p = 0; p < Ncl; ++p) { 7899 PetscInt pnt = points[2 * p], fdof; 7900 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7901 7902 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7903 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7904 if (flip) { 7905 PetscInt i, j, k; 7906 7907 if (!valCopy) { 7908 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7909 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7910 *values = valCopy; 7911 } 7912 for (i = 0; i < fdof; ++i) { 7913 PetscScalar fval = flip[i]; 7914 7915 if (multiplyRight) { 7916 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 7917 } 7918 if (multiplyLeft) { 7919 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 7920 } 7921 } 7922 } 7923 foffset += fdof; 7924 } 7925 } 7926 } 7927 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7928 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 7929 if (NclC) { 7930 if (multiplyRight) { *numCols = nCols = NiC; } 7931 if (multiplyLeft) { *numRows = nRows = NiC; } 7932 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7933 for (f = 0; f < PetscMax(1, Nf); ++f) { 7934 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7935 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7936 } 7937 for (f = 0; f < PetscMax(1, Nf); ++f) { 7938 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7939 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7940 } 7941 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7942 Ncl = NclC; 7943 Ni = NiC; 7944 points = pointsC; 7945 if (values) *values = valuesC; 7946 } 7947 /* 5) Calculate indices */ 7948 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7949 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 7950 if (Nf) { 7951 PetscInt idxOff; 7952 PetscBool useFieldOffsets; 7953 7954 if (outOffsets) { 7955 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7956 } 7957 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7958 if (useFieldOffsets) { 7959 for (p = 0; p < Ncl; ++p) { 7960 const PetscInt pnt = points[p * 2]; 7961 7962 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7963 } 7964 } else { 7965 for (p = 0; p < Ncl; ++p) { 7966 const PetscInt pnt = points[p * 2]; 7967 7968 if (pnt < idxStart || pnt >= idxEnd) continue; 7969 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7970 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7971 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7972 * global section. */ 7973 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7974 } 7975 } 7976 } else { 7977 PetscInt off = 0, idxOff; 7978 7979 for (p = 0; p < Ncl; ++p) { 7980 const PetscInt pnt = points[p * 2]; 7981 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7982 7983 if (pnt < idxStart || pnt >= idxEnd) continue; 7984 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7985 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7986 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7987 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7988 } 7989 } 7990 /* 6) Cleanup */ 7991 for (f = 0; f < PetscMax(1, Nf); ++f) { 7992 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7993 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7994 } 7995 if (NclC) { 7996 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7997 } else { 7998 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7999 } 8000 8001 if (indices) *indices = idx; 8002 PetscFunctionReturn(PETSC_SUCCESS); 8003 } 8004 8005 /*@C 8006 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8007 8008 Not collective 8009 8010 Input Parameters: 8011 + dm - The `DM` 8012 . section - The `PetscSection` describing the points (a local section) 8013 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8014 . point - The point defining the closure 8015 - useClPerm - Use the closure point permutation if available 8016 8017 Output Parameters: 8018 + numIndices - The number of dof indices in the closure of point with the input sections 8019 . indices - The dof indices 8020 . outOffsets - Array to write the field offsets into, or `NULL` 8021 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8022 8023 Level: advanced 8024 8025 Notes: 8026 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 8027 8028 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8029 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8030 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8031 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8032 indices (with the above semantics) are implied. 8033 8034 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8035 `PetscSection`, `DMGetGlobalSection()` 8036 @*/ 8037 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8038 { 8039 PetscInt numRows = -1, numCols = -1; 8040 8041 PetscFunctionBeginHot; 8042 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8043 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8044 *numIndices = numRows; 8045 PetscFunctionReturn(PETSC_SUCCESS); 8046 } 8047 8048 /*@C 8049 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8050 8051 Not collective 8052 8053 Input Parameters: 8054 + dm - The `DM` 8055 . section - The `PetscSection` describing the points (a local section) 8056 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8057 . point - The point defining the closure 8058 - useClPerm - Use the closure point permutation if available 8059 8060 Output Parameters: 8061 + numIndices - The number of dof indices in the closure of point with the input sections 8062 . indices - The dof indices 8063 . outOffsets - Array to write the field offsets into, or `NULL` 8064 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8065 8066 Level: advanced 8067 8068 Notes: 8069 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8070 8071 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8072 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8073 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8074 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8075 indices (with the above semantics) are implied. 8076 8077 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8078 @*/ 8079 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8080 { 8081 PetscFunctionBegin; 8082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8083 PetscAssertPointer(indices, 7); 8084 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8085 PetscFunctionReturn(PETSC_SUCCESS); 8086 } 8087 8088 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8089 { 8090 DM_Plex *mesh = (DM_Plex *)dm->data; 8091 PetscInt *indices; 8092 PetscInt numIndices; 8093 const PetscScalar *valuesOrig = values; 8094 PetscErrorCode ierr; 8095 8096 PetscFunctionBegin; 8097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8098 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8099 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8100 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8101 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8102 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8103 8104 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8105 8106 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8107 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8108 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8109 if (ierr) { 8110 PetscMPIInt rank; 8111 8112 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8113 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8114 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8115 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8116 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8117 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8118 } 8119 if (mesh->printFEM > 1) { 8120 PetscInt i; 8121 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8122 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8123 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8124 } 8125 8126 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8127 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8128 PetscFunctionReturn(PETSC_SUCCESS); 8129 } 8130 8131 /*@C 8132 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8133 8134 Not collective 8135 8136 Input Parameters: 8137 + dm - The `DM` 8138 . section - The section describing the layout in `v`, or `NULL` to use the default section 8139 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8140 . A - The matrix 8141 . point - The point in the `DM` 8142 . values - The array of values 8143 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8144 8145 Level: intermediate 8146 8147 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8148 @*/ 8149 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8150 { 8151 PetscFunctionBegin; 8152 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8153 PetscFunctionReturn(PETSC_SUCCESS); 8154 } 8155 8156 /*@C 8157 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8158 8159 Not collective 8160 8161 Input Parameters: 8162 + dmRow - The `DM` for the row fields 8163 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8164 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8165 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8166 . dmCol - The `DM` for the column fields 8167 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8168 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8169 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8170 . A - The matrix 8171 . point - The point in the `DM` 8172 . values - The array of values 8173 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8174 8175 Level: intermediate 8176 8177 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8178 @*/ 8179 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) 8180 { 8181 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8182 PetscInt *indicesRow, *indicesCol; 8183 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8184 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8185 8186 PetscErrorCode ierr; 8187 8188 PetscFunctionBegin; 8189 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8190 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8191 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8192 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8193 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8194 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8195 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8196 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8197 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8198 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8199 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8200 8201 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8202 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8203 valuesV1 = valuesV0; 8204 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8205 valuesV2 = valuesV1; 8206 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8207 8208 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8209 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8210 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8211 if (ierr) { 8212 PetscMPIInt rank; 8213 8214 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8215 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8216 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8217 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8218 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8219 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8220 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8221 } 8222 8223 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8224 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8225 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8226 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8227 PetscFunctionReturn(PETSC_SUCCESS); 8228 } 8229 8230 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8231 { 8232 DM_Plex *mesh = (DM_Plex *)dmf->data; 8233 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8234 PetscInt *cpoints = NULL; 8235 PetscInt *findices, *cindices; 8236 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8237 PetscInt foffsets[32], coffsets[32]; 8238 DMPolytopeType ct; 8239 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8240 PetscErrorCode ierr; 8241 8242 PetscFunctionBegin; 8243 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8244 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8245 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8246 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8247 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8248 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8249 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8250 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8251 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8252 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8253 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8254 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8255 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8256 PetscCall(PetscArrayzero(foffsets, 32)); 8257 PetscCall(PetscArrayzero(coffsets, 32)); 8258 /* Column indices */ 8259 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8260 maxFPoints = numCPoints; 8261 /* Compress out points not in the section */ 8262 /* TODO: Squeeze out points with 0 dof as well */ 8263 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8264 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8265 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8266 cpoints[q * 2] = cpoints[p]; 8267 cpoints[q * 2 + 1] = cpoints[p + 1]; 8268 ++q; 8269 } 8270 } 8271 numCPoints = q; 8272 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8273 PetscInt fdof; 8274 8275 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8276 if (!dof) continue; 8277 for (f = 0; f < numFields; ++f) { 8278 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8279 coffsets[f + 1] += fdof; 8280 } 8281 numCIndices += dof; 8282 } 8283 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8284 /* Row indices */ 8285 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8286 { 8287 DMPlexTransform tr; 8288 DMPolytopeType *rct; 8289 PetscInt *rsize, *rcone, *rornt, Nt; 8290 8291 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8292 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8293 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8294 numSubcells = rsize[Nt - 1]; 8295 PetscCall(DMPlexTransformDestroy(&tr)); 8296 } 8297 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8298 for (r = 0, q = 0; r < numSubcells; ++r) { 8299 /* TODO Map from coarse to fine cells */ 8300 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8301 /* Compress out points not in the section */ 8302 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8303 for (p = 0; p < numFPoints * 2; p += 2) { 8304 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8305 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8306 if (!dof) continue; 8307 for (s = 0; s < q; ++s) 8308 if (fpoints[p] == ftotpoints[s * 2]) break; 8309 if (s < q) continue; 8310 ftotpoints[q * 2] = fpoints[p]; 8311 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8312 ++q; 8313 } 8314 } 8315 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8316 } 8317 numFPoints = q; 8318 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8319 PetscInt fdof; 8320 8321 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8322 if (!dof) continue; 8323 for (f = 0; f < numFields; ++f) { 8324 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8325 foffsets[f + 1] += fdof; 8326 } 8327 numFIndices += dof; 8328 } 8329 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8330 8331 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8332 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8333 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8334 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8335 if (numFields) { 8336 const PetscInt **permsF[32] = {NULL}; 8337 const PetscInt **permsC[32] = {NULL}; 8338 8339 for (f = 0; f < numFields; f++) { 8340 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8341 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8342 } 8343 for (p = 0; p < numFPoints; p++) { 8344 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8345 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8346 } 8347 for (p = 0; p < numCPoints; p++) { 8348 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8349 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8350 } 8351 for (f = 0; f < numFields; f++) { 8352 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8353 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8354 } 8355 } else { 8356 const PetscInt **permsF = NULL; 8357 const PetscInt **permsC = NULL; 8358 8359 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8360 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8361 for (p = 0, off = 0; p < numFPoints; p++) { 8362 const PetscInt *perm = permsF ? permsF[p] : NULL; 8363 8364 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8365 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8366 } 8367 for (p = 0, off = 0; p < numCPoints; p++) { 8368 const PetscInt *perm = permsC ? permsC[p] : NULL; 8369 8370 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8371 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8372 } 8373 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8374 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8375 } 8376 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8377 /* TODO: flips */ 8378 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8379 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8380 if (ierr) { 8381 PetscMPIInt rank; 8382 8383 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8384 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8385 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8386 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8387 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8388 } 8389 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8390 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8391 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8392 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8393 PetscFunctionReturn(PETSC_SUCCESS); 8394 } 8395 8396 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8397 { 8398 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8399 PetscInt *cpoints = NULL; 8400 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8401 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8402 DMPolytopeType ct; 8403 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8404 8405 PetscFunctionBegin; 8406 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8407 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8408 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8409 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8410 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8411 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8412 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8413 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8414 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8415 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8416 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8417 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8418 /* Column indices */ 8419 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8420 maxFPoints = numCPoints; 8421 /* Compress out points not in the section */ 8422 /* TODO: Squeeze out points with 0 dof as well */ 8423 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8424 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8425 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8426 cpoints[q * 2] = cpoints[p]; 8427 cpoints[q * 2 + 1] = cpoints[p + 1]; 8428 ++q; 8429 } 8430 } 8431 numCPoints = q; 8432 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8433 PetscInt fdof; 8434 8435 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8436 if (!dof) continue; 8437 for (f = 0; f < numFields; ++f) { 8438 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8439 coffsets[f + 1] += fdof; 8440 } 8441 numCIndices += dof; 8442 } 8443 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8444 /* Row indices */ 8445 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8446 { 8447 DMPlexTransform tr; 8448 DMPolytopeType *rct; 8449 PetscInt *rsize, *rcone, *rornt, Nt; 8450 8451 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8452 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8453 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8454 numSubcells = rsize[Nt - 1]; 8455 PetscCall(DMPlexTransformDestroy(&tr)); 8456 } 8457 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8458 for (r = 0, q = 0; r < numSubcells; ++r) { 8459 /* TODO Map from coarse to fine cells */ 8460 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8461 /* Compress out points not in the section */ 8462 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8463 for (p = 0; p < numFPoints * 2; p += 2) { 8464 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8465 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8466 if (!dof) continue; 8467 for (s = 0; s < q; ++s) 8468 if (fpoints[p] == ftotpoints[s * 2]) break; 8469 if (s < q) continue; 8470 ftotpoints[q * 2] = fpoints[p]; 8471 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8472 ++q; 8473 } 8474 } 8475 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8476 } 8477 numFPoints = q; 8478 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8479 PetscInt fdof; 8480 8481 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8482 if (!dof) continue; 8483 for (f = 0; f < numFields; ++f) { 8484 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8485 foffsets[f + 1] += fdof; 8486 } 8487 numFIndices += dof; 8488 } 8489 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8490 8491 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8492 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8493 if (numFields) { 8494 const PetscInt **permsF[32] = {NULL}; 8495 const PetscInt **permsC[32] = {NULL}; 8496 8497 for (f = 0; f < numFields; f++) { 8498 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8499 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8500 } 8501 for (p = 0; p < numFPoints; p++) { 8502 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8503 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8504 } 8505 for (p = 0; p < numCPoints; p++) { 8506 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8507 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8508 } 8509 for (f = 0; f < numFields; f++) { 8510 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8511 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8512 } 8513 } else { 8514 const PetscInt **permsF = NULL; 8515 const PetscInt **permsC = NULL; 8516 8517 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8518 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8519 for (p = 0, off = 0; p < numFPoints; p++) { 8520 const PetscInt *perm = permsF ? permsF[p] : NULL; 8521 8522 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8523 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8524 } 8525 for (p = 0, off = 0; p < numCPoints; p++) { 8526 const PetscInt *perm = permsC ? permsC[p] : NULL; 8527 8528 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8529 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8530 } 8531 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8532 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8533 } 8534 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8535 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8536 PetscFunctionReturn(PETSC_SUCCESS); 8537 } 8538 8539 /*@C 8540 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8541 8542 Input Parameter: 8543 . dm - The `DMPLEX` object 8544 8545 Output Parameter: 8546 . cellHeight - The height of a cell 8547 8548 Level: developer 8549 8550 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8551 @*/ 8552 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8553 { 8554 DM_Plex *mesh = (DM_Plex *)dm->data; 8555 8556 PetscFunctionBegin; 8557 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8558 PetscAssertPointer(cellHeight, 2); 8559 *cellHeight = mesh->vtkCellHeight; 8560 PetscFunctionReturn(PETSC_SUCCESS); 8561 } 8562 8563 /*@C 8564 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8565 8566 Input Parameters: 8567 + dm - The `DMPLEX` object 8568 - cellHeight - The height of a cell 8569 8570 Level: developer 8571 8572 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8573 @*/ 8574 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8575 { 8576 DM_Plex *mesh = (DM_Plex *)dm->data; 8577 8578 PetscFunctionBegin; 8579 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8580 mesh->vtkCellHeight = cellHeight; 8581 PetscFunctionReturn(PETSC_SUCCESS); 8582 } 8583 8584 /*@ 8585 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8586 8587 Input Parameters: 8588 + dm - The `DMPLEX` object 8589 - ct - The `DMPolytopeType` of the cell 8590 8591 Output Parameters: 8592 + start - The first cell of this type, or `NULL` 8593 - end - The upper bound on this celltype, or `NULL` 8594 8595 Level: advanced 8596 8597 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8598 @*/ 8599 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8600 { 8601 DM_Plex *mesh = (DM_Plex *)dm->data; 8602 DMLabel label; 8603 PetscInt pStart, pEnd; 8604 8605 PetscFunctionBegin; 8606 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8607 if (start) { 8608 PetscAssertPointer(start, 3); 8609 *start = 0; 8610 } 8611 if (end) { 8612 PetscAssertPointer(end, 4); 8613 *end = 0; 8614 } 8615 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8616 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8617 if (mesh->tr) { 8618 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8619 } else { 8620 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8621 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8622 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8623 } 8624 PetscFunctionReturn(PETSC_SUCCESS); 8625 } 8626 8627 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8628 { 8629 PetscSection section, globalSection; 8630 PetscInt *numbers, p; 8631 8632 PetscFunctionBegin; 8633 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8634 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8635 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8636 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8637 PetscCall(PetscSectionSetUp(section)); 8638 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8639 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8640 for (p = pStart; p < pEnd; ++p) { 8641 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8642 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8643 else numbers[p - pStart] += shift; 8644 } 8645 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8646 if (globalSize) { 8647 PetscLayout layout; 8648 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8649 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8650 PetscCall(PetscLayoutDestroy(&layout)); 8651 } 8652 PetscCall(PetscSectionDestroy(§ion)); 8653 PetscCall(PetscSectionDestroy(&globalSection)); 8654 PetscFunctionReturn(PETSC_SUCCESS); 8655 } 8656 8657 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8658 { 8659 PetscInt cellHeight, cStart, cEnd; 8660 8661 PetscFunctionBegin; 8662 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8663 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8664 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8665 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8666 PetscFunctionReturn(PETSC_SUCCESS); 8667 } 8668 8669 /*@ 8670 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8671 8672 Input Parameter: 8673 . dm - The `DMPLEX` object 8674 8675 Output Parameter: 8676 . globalCellNumbers - Global cell numbers for all cells on this process 8677 8678 Level: developer 8679 8680 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8681 @*/ 8682 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8683 { 8684 DM_Plex *mesh = (DM_Plex *)dm->data; 8685 8686 PetscFunctionBegin; 8687 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8688 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8689 *globalCellNumbers = mesh->globalCellNumbers; 8690 PetscFunctionReturn(PETSC_SUCCESS); 8691 } 8692 8693 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8694 { 8695 PetscInt vStart, vEnd; 8696 8697 PetscFunctionBegin; 8698 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8699 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8700 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8701 PetscFunctionReturn(PETSC_SUCCESS); 8702 } 8703 8704 /*@ 8705 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8706 8707 Input Parameter: 8708 . dm - The `DMPLEX` object 8709 8710 Output Parameter: 8711 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8712 8713 Level: developer 8714 8715 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8716 @*/ 8717 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8718 { 8719 DM_Plex *mesh = (DM_Plex *)dm->data; 8720 8721 PetscFunctionBegin; 8722 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8723 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8724 *globalVertexNumbers = mesh->globalVertexNumbers; 8725 PetscFunctionReturn(PETSC_SUCCESS); 8726 } 8727 8728 /*@ 8729 DMPlexCreatePointNumbering - Create a global numbering for all points. 8730 8731 Collective 8732 8733 Input Parameter: 8734 . dm - The `DMPLEX` object 8735 8736 Output Parameter: 8737 . globalPointNumbers - Global numbers for all points on this process 8738 8739 Level: developer 8740 8741 Notes: 8742 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8743 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8744 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8745 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8746 8747 The partitioned mesh is 8748 ``` 8749 (2)--0--(3)--1--(4) (1)--0--(2) 8750 ``` 8751 and its global numbering is 8752 ``` 8753 (3)--0--(4)--1--(5)--2--(6) 8754 ``` 8755 Then the global numbering is provided as 8756 ``` 8757 [0] Number of indices in set 5 8758 [0] 0 0 8759 [0] 1 1 8760 [0] 2 3 8761 [0] 3 4 8762 [0] 4 -6 8763 [1] Number of indices in set 3 8764 [1] 0 2 8765 [1] 1 5 8766 [1] 2 6 8767 ``` 8768 8769 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8770 @*/ 8771 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8772 { 8773 IS nums[4]; 8774 PetscInt depths[4], gdepths[4], starts[4]; 8775 PetscInt depth, d, shift = 0; 8776 PetscBool empty = PETSC_FALSE; 8777 8778 PetscFunctionBegin; 8779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8780 PetscCall(DMPlexGetDepth(dm, &depth)); 8781 // For unstratified meshes use dim instead of depth 8782 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8783 // If any stratum is empty, we must mark all empty 8784 for (d = 0; d <= depth; ++d) { 8785 PetscInt end; 8786 8787 depths[d] = depth - d; 8788 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8789 if (!(starts[d] - end)) empty = PETSC_TRUE; 8790 } 8791 if (empty) 8792 for (d = 0; d <= depth; ++d) { 8793 depths[d] = -1; 8794 starts[d] = -1; 8795 } 8796 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8797 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8798 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]); 8799 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8800 for (d = 0; d <= depth; ++d) { 8801 PetscInt pStart, pEnd, gsize; 8802 8803 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8804 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8805 shift += gsize; 8806 } 8807 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8808 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8809 PetscFunctionReturn(PETSC_SUCCESS); 8810 } 8811 8812 /*@ 8813 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8814 8815 Input Parameter: 8816 . dm - The `DMPLEX` object 8817 8818 Output Parameter: 8819 . ranks - The rank field 8820 8821 Options Database Key: 8822 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8823 8824 Level: intermediate 8825 8826 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8827 @*/ 8828 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8829 { 8830 DM rdm; 8831 PetscFE fe; 8832 PetscScalar *r; 8833 PetscMPIInt rank; 8834 DMPolytopeType ct; 8835 PetscInt dim, cStart, cEnd, c; 8836 PetscBool simplex; 8837 8838 PetscFunctionBeginUser; 8839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8840 PetscAssertPointer(ranks, 2); 8841 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8842 PetscCall(DMClone(dm, &rdm)); 8843 PetscCall(DMGetDimension(rdm, &dim)); 8844 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8845 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8846 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8847 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8848 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8849 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8850 PetscCall(PetscFEDestroy(&fe)); 8851 PetscCall(DMCreateDS(rdm)); 8852 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8853 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8854 PetscCall(VecGetArray(*ranks, &r)); 8855 for (c = cStart; c < cEnd; ++c) { 8856 PetscScalar *lr; 8857 8858 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8859 if (lr) *lr = rank; 8860 } 8861 PetscCall(VecRestoreArray(*ranks, &r)); 8862 PetscCall(DMDestroy(&rdm)); 8863 PetscFunctionReturn(PETSC_SUCCESS); 8864 } 8865 8866 /*@ 8867 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8868 8869 Input Parameters: 8870 + dm - The `DMPLEX` 8871 - label - The `DMLabel` 8872 8873 Output Parameter: 8874 . val - The label value field 8875 8876 Options Database Key: 8877 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8878 8879 Level: intermediate 8880 8881 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8882 @*/ 8883 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8884 { 8885 DM rdm, plex; 8886 Vec lval; 8887 PetscSection section; 8888 PetscFE fe; 8889 PetscScalar *v; 8890 PetscInt dim, pStart, pEnd, p, cStart; 8891 DMPolytopeType ct; 8892 char name[PETSC_MAX_PATH_LEN]; 8893 const char *lname, *prefix; 8894 8895 PetscFunctionBeginUser; 8896 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8897 PetscAssertPointer(label, 2); 8898 PetscAssertPointer(val, 3); 8899 PetscCall(DMClone(dm, &rdm)); 8900 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8901 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8902 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8903 PetscCall(DMDestroy(&plex)); 8904 PetscCall(DMGetDimension(rdm, &dim)); 8905 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8906 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8907 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8908 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8909 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8910 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8911 PetscCall(PetscFEDestroy(&fe)); 8912 PetscCall(DMCreateDS(rdm)); 8913 PetscCall(DMCreateGlobalVector(rdm, val)); 8914 PetscCall(DMCreateLocalVector(rdm, &lval)); 8915 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8916 PetscCall(DMGetLocalSection(rdm, §ion)); 8917 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8918 PetscCall(VecGetArray(lval, &v)); 8919 for (p = pStart; p < pEnd; ++p) { 8920 PetscInt cval, dof, off; 8921 8922 PetscCall(PetscSectionGetDof(section, p, &dof)); 8923 if (!dof) continue; 8924 PetscCall(DMLabelGetValue(label, p, &cval)); 8925 PetscCall(PetscSectionGetOffset(section, p, &off)); 8926 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 8927 } 8928 PetscCall(VecRestoreArray(lval, &v)); 8929 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 8930 PetscCall(VecDestroy(&lval)); 8931 PetscCall(DMDestroy(&rdm)); 8932 PetscFunctionReturn(PETSC_SUCCESS); 8933 } 8934 8935 /*@ 8936 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8937 8938 Input Parameter: 8939 . dm - The `DMPLEX` object 8940 8941 Level: developer 8942 8943 Notes: 8944 This is a useful diagnostic when creating meshes programmatically. 8945 8946 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8947 8948 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8949 @*/ 8950 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8951 { 8952 PetscSection coneSection, supportSection; 8953 const PetscInt *cone, *support; 8954 PetscInt coneSize, c, supportSize, s; 8955 PetscInt pStart, pEnd, p, pp, csize, ssize; 8956 PetscBool storagecheck = PETSC_TRUE; 8957 8958 PetscFunctionBegin; 8959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8960 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8961 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8962 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8963 /* Check that point p is found in the support of its cone points, and vice versa */ 8964 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8965 for (p = pStart; p < pEnd; ++p) { 8966 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8967 PetscCall(DMPlexGetCone(dm, p, &cone)); 8968 for (c = 0; c < coneSize; ++c) { 8969 PetscBool dup = PETSC_FALSE; 8970 PetscInt d; 8971 for (d = c - 1; d >= 0; --d) { 8972 if (cone[c] == cone[d]) { 8973 dup = PETSC_TRUE; 8974 break; 8975 } 8976 } 8977 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8978 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8979 for (s = 0; s < supportSize; ++s) { 8980 if (support[s] == p) break; 8981 } 8982 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8983 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8984 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8985 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8986 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8987 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8988 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8989 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]); 8990 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8991 } 8992 } 8993 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8994 if (p != pp) { 8995 storagecheck = PETSC_FALSE; 8996 continue; 8997 } 8998 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8999 PetscCall(DMPlexGetSupport(dm, p, &support)); 9000 for (s = 0; s < supportSize; ++s) { 9001 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9002 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9003 for (c = 0; c < coneSize; ++c) { 9004 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9005 if (cone[c] != pp) { 9006 c = 0; 9007 break; 9008 } 9009 if (cone[c] == p) break; 9010 } 9011 if (c >= coneSize) { 9012 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9013 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9014 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9015 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9016 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9017 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9018 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9019 } 9020 } 9021 } 9022 if (storagecheck) { 9023 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9024 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9025 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9026 } 9027 PetscFunctionReturn(PETSC_SUCCESS); 9028 } 9029 9030 /* 9031 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. 9032 */ 9033 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9034 { 9035 DMPolytopeType cct; 9036 PetscInt ptpoints[4]; 9037 const PetscInt *cone, *ccone, *ptcone; 9038 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9039 9040 PetscFunctionBegin; 9041 *unsplit = 0; 9042 switch (ct) { 9043 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9044 ptpoints[npt++] = c; 9045 break; 9046 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9047 PetscCall(DMPlexGetCone(dm, c, &cone)); 9048 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9049 for (cp = 0; cp < coneSize; ++cp) { 9050 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9051 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9052 } 9053 break; 9054 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9055 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9056 PetscCall(DMPlexGetCone(dm, c, &cone)); 9057 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9058 for (cp = 0; cp < coneSize; ++cp) { 9059 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9060 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9061 for (ccp = 0; ccp < cconeSize; ++ccp) { 9062 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9063 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9064 PetscInt p; 9065 for (p = 0; p < npt; ++p) 9066 if (ptpoints[p] == ccone[ccp]) break; 9067 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9068 } 9069 } 9070 } 9071 break; 9072 default: 9073 break; 9074 } 9075 for (pt = 0; pt < npt; ++pt) { 9076 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9077 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9078 } 9079 PetscFunctionReturn(PETSC_SUCCESS); 9080 } 9081 9082 /*@ 9083 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9084 9085 Input Parameters: 9086 + dm - The `DMPLEX` object 9087 - cellHeight - Normally 0 9088 9089 Level: developer 9090 9091 Notes: 9092 This is a useful diagnostic when creating meshes programmatically. 9093 Currently applicable only to homogeneous simplex or tensor meshes. 9094 9095 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9096 9097 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9098 @*/ 9099 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9100 { 9101 DMPlexInterpolatedFlag interp; 9102 DMPolytopeType ct; 9103 PetscInt vStart, vEnd, cStart, cEnd, c; 9104 9105 PetscFunctionBegin; 9106 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9107 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9108 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9109 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9110 for (c = cStart; c < cEnd; ++c) { 9111 PetscInt *closure = NULL; 9112 PetscInt coneSize, closureSize, cl, Nv = 0; 9113 9114 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9115 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9116 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9117 if (interp == DMPLEX_INTERPOLATED_FULL) { 9118 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9119 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)); 9120 } 9121 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9122 for (cl = 0; cl < closureSize * 2; cl += 2) { 9123 const PetscInt p = closure[cl]; 9124 if ((p >= vStart) && (p < vEnd)) ++Nv; 9125 } 9126 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9127 /* Special Case: Tensor faces with identified vertices */ 9128 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9129 PetscInt unsplit; 9130 9131 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9132 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9133 } 9134 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)); 9135 } 9136 PetscFunctionReturn(PETSC_SUCCESS); 9137 } 9138 9139 /*@ 9140 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9141 9142 Collective 9143 9144 Input Parameters: 9145 + dm - The `DMPLEX` object 9146 - cellHeight - Normally 0 9147 9148 Level: developer 9149 9150 Notes: 9151 This is a useful diagnostic when creating meshes programmatically. 9152 This routine is only relevant for meshes that are fully interpolated across all ranks. 9153 It will error out if a partially interpolated mesh is given on some rank. 9154 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9155 9156 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9157 9158 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9159 @*/ 9160 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9161 { 9162 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9163 DMPlexInterpolatedFlag interpEnum; 9164 9165 PetscFunctionBegin; 9166 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9167 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9168 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9169 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9170 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9171 PetscFunctionReturn(PETSC_SUCCESS); 9172 } 9173 9174 PetscCall(DMGetDimension(dm, &dim)); 9175 PetscCall(DMPlexGetDepth(dm, &depth)); 9176 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9177 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9178 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9179 for (c = cStart; c < cEnd; ++c) { 9180 const PetscInt *cone, *ornt, *faceSizes, *faces; 9181 const DMPolytopeType *faceTypes; 9182 DMPolytopeType ct; 9183 PetscInt numFaces, coneSize, f; 9184 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9185 9186 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9187 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9188 if (unsplit) continue; 9189 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9190 PetscCall(DMPlexGetCone(dm, c, &cone)); 9191 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9192 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9193 for (cl = 0; cl < closureSize * 2; cl += 2) { 9194 const PetscInt p = closure[cl]; 9195 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9196 } 9197 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9198 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); 9199 for (f = 0; f < numFaces; ++f) { 9200 DMPolytopeType fct; 9201 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9202 9203 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9204 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9205 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9206 const PetscInt p = fclosure[cl]; 9207 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9208 } 9209 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]); 9210 for (v = 0; v < fnumCorners; ++v) { 9211 if (fclosure[v] != faces[fOff + v]) { 9212 PetscInt v1; 9213 9214 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9215 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9216 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9217 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9218 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9219 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]); 9220 } 9221 } 9222 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9223 fOff += faceSizes[f]; 9224 } 9225 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9226 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9227 } 9228 } 9229 PetscFunctionReturn(PETSC_SUCCESS); 9230 } 9231 9232 /*@ 9233 DMPlexCheckGeometry - Check the geometry of mesh cells 9234 9235 Input Parameter: 9236 . dm - The `DMPLEX` object 9237 9238 Level: developer 9239 9240 Notes: 9241 This is a useful diagnostic when creating meshes programmatically. 9242 9243 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9244 9245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9246 @*/ 9247 PetscErrorCode DMPlexCheckGeometry(DM dm) 9248 { 9249 Vec coordinates; 9250 PetscReal detJ, J[9], refVol = 1.0; 9251 PetscReal vol; 9252 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9253 9254 PetscFunctionBegin; 9255 PetscCall(DMGetDimension(dm, &dim)); 9256 PetscCall(DMGetCoordinateDim(dm, &dE)); 9257 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9258 PetscCall(DMPlexGetDepth(dm, &depth)); 9259 for (d = 0; d < dim; ++d) refVol *= 2.0; 9260 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9261 /* Make sure local coordinates are created, because that step is collective */ 9262 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9263 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9264 for (c = cStart; c < cEnd; ++c) { 9265 DMPolytopeType ct; 9266 PetscInt unsplit; 9267 PetscBool ignoreZeroVol = PETSC_FALSE; 9268 9269 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9270 switch (ct) { 9271 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9272 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9273 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9274 ignoreZeroVol = PETSC_TRUE; 9275 break; 9276 default: 9277 break; 9278 } 9279 switch (ct) { 9280 case DM_POLYTOPE_TRI_PRISM: 9281 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9282 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9283 case DM_POLYTOPE_PYRAMID: 9284 continue; 9285 default: 9286 break; 9287 } 9288 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9289 if (unsplit) continue; 9290 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9291 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); 9292 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9293 /* This should work with periodicity since DG coordinates should be used */ 9294 if (depth > 1) { 9295 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9296 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); 9297 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9298 } 9299 } 9300 PetscFunctionReturn(PETSC_SUCCESS); 9301 } 9302 9303 /*@ 9304 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9305 9306 Collective 9307 9308 Input Parameters: 9309 + dm - The `DMPLEX` object 9310 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9311 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9312 9313 Level: developer 9314 9315 Notes: 9316 This is mainly intended for debugging/testing purposes. 9317 9318 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9319 9320 Extra roots can come from periodic cuts, where additional points appear on the boundary 9321 9322 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9323 @*/ 9324 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9325 { 9326 PetscInt l, nleaves, nroots, overlap; 9327 const PetscInt *locals; 9328 const PetscSFNode *remotes; 9329 PetscBool distributed; 9330 MPI_Comm comm; 9331 PetscMPIInt rank; 9332 9333 PetscFunctionBegin; 9334 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9335 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9336 else pointSF = dm->sf; 9337 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9338 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9339 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9340 { 9341 PetscMPIInt mpiFlag; 9342 9343 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9344 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9345 } 9346 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9347 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9348 if (!distributed) { 9349 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); 9350 PetscFunctionReturn(PETSC_SUCCESS); 9351 } 9352 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); 9353 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9354 9355 /* Check SF graph is compatible with DMPlex chart */ 9356 { 9357 PetscInt pStart, pEnd, maxLeaf; 9358 9359 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9360 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9361 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9362 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9363 } 9364 9365 /* Check Point SF has no local points referenced */ 9366 for (l = 0; l < nleaves; l++) { 9367 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); 9368 } 9369 9370 /* Check there are no cells in interface */ 9371 if (!overlap) { 9372 PetscInt cellHeight, cStart, cEnd; 9373 9374 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9375 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9376 for (l = 0; l < nleaves; ++l) { 9377 const PetscInt point = locals ? locals[l] : l; 9378 9379 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9380 } 9381 } 9382 9383 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9384 { 9385 const PetscInt *rootdegree; 9386 9387 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9388 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9389 for (l = 0; l < nleaves; ++l) { 9390 const PetscInt point = locals ? locals[l] : l; 9391 const PetscInt *cone; 9392 PetscInt coneSize, c, idx; 9393 9394 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9395 PetscCall(DMPlexGetCone(dm, point, &cone)); 9396 for (c = 0; c < coneSize; ++c) { 9397 if (!rootdegree[cone[c]]) { 9398 if (locals) { 9399 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9400 } else { 9401 idx = (cone[c] < nleaves) ? cone[c] : -1; 9402 } 9403 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9404 } 9405 } 9406 } 9407 } 9408 PetscFunctionReturn(PETSC_SUCCESS); 9409 } 9410 9411 /*@ 9412 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9413 9414 Input Parameter: 9415 . dm - The `DMPLEX` object 9416 9417 Level: developer 9418 9419 Notes: 9420 This is a useful diagnostic when creating meshes programmatically. 9421 9422 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9423 9424 Currently does not include `DMPlexCheckCellShape()`. 9425 9426 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9427 @*/ 9428 PetscErrorCode DMPlexCheck(DM dm) 9429 { 9430 PetscInt cellHeight; 9431 9432 PetscFunctionBegin; 9433 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9434 PetscCall(DMPlexCheckSymmetry(dm)); 9435 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9436 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9437 PetscCall(DMPlexCheckGeometry(dm)); 9438 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9439 PetscCall(DMPlexCheckInterfaceCones(dm)); 9440 PetscFunctionReturn(PETSC_SUCCESS); 9441 } 9442 9443 typedef struct cell_stats { 9444 PetscReal min, max, sum, squaresum; 9445 PetscInt count; 9446 } cell_stats_t; 9447 9448 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9449 { 9450 PetscInt i, N = *len; 9451 9452 for (i = 0; i < N; i++) { 9453 cell_stats_t *A = (cell_stats_t *)a; 9454 cell_stats_t *B = (cell_stats_t *)b; 9455 9456 B->min = PetscMin(A->min, B->min); 9457 B->max = PetscMax(A->max, B->max); 9458 B->sum += A->sum; 9459 B->squaresum += A->squaresum; 9460 B->count += A->count; 9461 } 9462 } 9463 9464 /*@ 9465 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9466 9467 Collective 9468 9469 Input Parameters: 9470 + dm - The `DMPLEX` object 9471 . output - If true, statistics will be displayed on `stdout` 9472 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9473 9474 Level: developer 9475 9476 Notes: 9477 This is mainly intended for debugging/testing purposes. 9478 9479 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9480 9481 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9482 @*/ 9483 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9484 { 9485 DM dmCoarse; 9486 cell_stats_t stats, globalStats; 9487 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9488 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9489 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9490 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9491 PetscMPIInt rank, size; 9492 9493 PetscFunctionBegin; 9494 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9495 stats.min = PETSC_MAX_REAL; 9496 stats.max = PETSC_MIN_REAL; 9497 stats.sum = stats.squaresum = 0.; 9498 stats.count = 0; 9499 9500 PetscCallMPI(MPI_Comm_size(comm, &size)); 9501 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9502 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9503 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9504 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9505 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9506 for (c = cStart; c < cEnd; c++) { 9507 PetscInt i; 9508 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9509 9510 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9511 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9512 for (i = 0; i < PetscSqr(cdim); ++i) { 9513 frobJ += J[i] * J[i]; 9514 frobInvJ += invJ[i] * invJ[i]; 9515 } 9516 cond2 = frobJ * frobInvJ; 9517 cond = PetscSqrtReal(cond2); 9518 9519 stats.min = PetscMin(stats.min, cond); 9520 stats.max = PetscMax(stats.max, cond); 9521 stats.sum += cond; 9522 stats.squaresum += cond2; 9523 stats.count++; 9524 if (output && cond > limit) { 9525 PetscSection coordSection; 9526 Vec coordsLocal; 9527 PetscScalar *coords = NULL; 9528 PetscInt Nv, d, clSize, cl, *closure = NULL; 9529 9530 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9531 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9532 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9533 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9534 for (i = 0; i < Nv / cdim; ++i) { 9535 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9536 for (d = 0; d < cdim; ++d) { 9537 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9538 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9539 } 9540 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9541 } 9542 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9543 for (cl = 0; cl < clSize * 2; cl += 2) { 9544 const PetscInt edge = closure[cl]; 9545 9546 if ((edge >= eStart) && (edge < eEnd)) { 9547 PetscReal len; 9548 9549 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9550 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9551 } 9552 } 9553 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9554 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9555 } 9556 } 9557 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9558 9559 if (size > 1) { 9560 PetscMPIInt blockLengths[2] = {4, 1}; 9561 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9562 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9563 MPI_Op statReduce; 9564 9565 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9566 PetscCallMPI(MPI_Type_commit(&statType)); 9567 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9568 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9569 PetscCallMPI(MPI_Op_free(&statReduce)); 9570 PetscCallMPI(MPI_Type_free(&statType)); 9571 } else { 9572 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9573 } 9574 if (rank == 0) { 9575 count = globalStats.count; 9576 min = globalStats.min; 9577 max = globalStats.max; 9578 mean = globalStats.sum / globalStats.count; 9579 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9580 } 9581 9582 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)); 9583 PetscCall(PetscFree2(J, invJ)); 9584 9585 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9586 if (dmCoarse) { 9587 PetscBool isplex; 9588 9589 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9590 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9591 } 9592 PetscFunctionReturn(PETSC_SUCCESS); 9593 } 9594 9595 /*@ 9596 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9597 orthogonal quality below given tolerance. 9598 9599 Collective 9600 9601 Input Parameters: 9602 + dm - The `DMPLEX` object 9603 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9604 - atol - [0, 1] Absolute tolerance for tagging cells. 9605 9606 Output Parameters: 9607 + OrthQual - `Vec` containing orthogonal quality per cell 9608 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9609 9610 Options Database Keys: 9611 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9612 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9613 9614 Level: intermediate 9615 9616 Notes: 9617 Orthogonal quality is given by the following formula\: 9618 9619 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9620 9621 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 9622 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9623 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9624 calculating the cosine of the angle between these vectors. 9625 9626 Orthogonal quality ranges from 1 (best) to 0 (worst). 9627 9628 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9629 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9630 9631 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9632 9633 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9634 @*/ 9635 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9636 { 9637 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9638 PetscInt *idx; 9639 PetscScalar *oqVals; 9640 const PetscScalar *cellGeomArr, *faceGeomArr; 9641 PetscReal *ci, *fi, *Ai; 9642 MPI_Comm comm; 9643 Vec cellgeom, facegeom; 9644 DM dmFace, dmCell; 9645 IS glob; 9646 ISLocalToGlobalMapping ltog; 9647 PetscViewer vwr; 9648 9649 PetscFunctionBegin; 9650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9651 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9652 PetscAssertPointer(OrthQual, 4); 9653 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9654 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9655 PetscCall(DMGetDimension(dm, &nc)); 9656 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9657 { 9658 DMPlexInterpolatedFlag interpFlag; 9659 9660 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9661 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9662 PetscMPIInt rank; 9663 9664 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9665 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9666 } 9667 } 9668 if (OrthQualLabel) { 9669 PetscAssertPointer(OrthQualLabel, 5); 9670 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9671 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9672 } else { 9673 *OrthQualLabel = NULL; 9674 } 9675 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9676 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9677 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9678 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9679 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9680 PetscCall(VecCreate(comm, OrthQual)); 9681 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9682 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9683 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9684 PetscCall(VecSetUp(*OrthQual)); 9685 PetscCall(ISDestroy(&glob)); 9686 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9687 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9688 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9689 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9690 PetscCall(VecGetDM(cellgeom, &dmCell)); 9691 PetscCall(VecGetDM(facegeom, &dmFace)); 9692 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9693 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9694 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9695 PetscInt cellarr[2], *adj = NULL; 9696 PetscScalar *cArr, *fArr; 9697 PetscReal minvalc = 1.0, minvalf = 1.0; 9698 PetscFVCellGeom *cg; 9699 9700 idx[cellIter] = cell - cStart; 9701 cellarr[0] = cell; 9702 /* Make indexing into cellGeom easier */ 9703 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9704 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9705 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9706 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9707 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9708 PetscInt i; 9709 const PetscInt neigh = adj[cellneigh]; 9710 PetscReal normci = 0, normfi = 0, normai = 0; 9711 PetscFVCellGeom *cgneigh; 9712 PetscFVFaceGeom *fg; 9713 9714 /* Don't count ourselves in the neighbor list */ 9715 if (neigh == cell) continue; 9716 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9717 cellarr[1] = neigh; 9718 { 9719 PetscInt numcovpts; 9720 const PetscInt *covpts; 9721 9722 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9723 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9724 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9725 } 9726 9727 /* Compute c_i, f_i and their norms */ 9728 for (i = 0; i < nc; i++) { 9729 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9730 fi[i] = fg->centroid[i] - cg->centroid[i]; 9731 Ai[i] = fg->normal[i]; 9732 normci += PetscPowReal(ci[i], 2); 9733 normfi += PetscPowReal(fi[i], 2); 9734 normai += PetscPowReal(Ai[i], 2); 9735 } 9736 normci = PetscSqrtReal(normci); 9737 normfi = PetscSqrtReal(normfi); 9738 normai = PetscSqrtReal(normai); 9739 9740 /* Normalize and compute for each face-cell-normal pair */ 9741 for (i = 0; i < nc; i++) { 9742 ci[i] = ci[i] / normci; 9743 fi[i] = fi[i] / normfi; 9744 Ai[i] = Ai[i] / normai; 9745 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9746 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9747 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9748 } 9749 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9750 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9751 } 9752 PetscCall(PetscFree(adj)); 9753 PetscCall(PetscFree2(cArr, fArr)); 9754 /* Defer to cell if they're equal */ 9755 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9756 if (OrthQualLabel) { 9757 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9758 } 9759 } 9760 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9761 PetscCall(VecAssemblyBegin(*OrthQual)); 9762 PetscCall(VecAssemblyEnd(*OrthQual)); 9763 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9764 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9765 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9766 if (OrthQualLabel) { 9767 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9768 } 9769 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9770 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9771 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9772 PetscFunctionReturn(PETSC_SUCCESS); 9773 } 9774 9775 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9776 * interpolator construction */ 9777 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9778 { 9779 PetscSection section, newSection, gsection; 9780 PetscSF sf; 9781 PetscBool hasConstraints, ghasConstraints; 9782 9783 PetscFunctionBegin; 9784 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9785 PetscAssertPointer(odm, 2); 9786 PetscCall(DMGetLocalSection(dm, §ion)); 9787 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9788 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9789 if (!ghasConstraints) { 9790 PetscCall(PetscObjectReference((PetscObject)dm)); 9791 *odm = dm; 9792 PetscFunctionReturn(PETSC_SUCCESS); 9793 } 9794 PetscCall(DMClone(dm, odm)); 9795 PetscCall(DMCopyFields(dm, *odm)); 9796 PetscCall(DMGetLocalSection(*odm, &newSection)); 9797 PetscCall(DMGetPointSF(*odm, &sf)); 9798 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9799 PetscCall(DMSetGlobalSection(*odm, gsection)); 9800 PetscCall(PetscSectionDestroy(&gsection)); 9801 PetscFunctionReturn(PETSC_SUCCESS); 9802 } 9803 9804 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9805 { 9806 DM dmco, dmfo; 9807 Mat interpo; 9808 Vec rscale; 9809 Vec cglobalo, clocal; 9810 Vec fglobal, fglobalo, flocal; 9811 PetscBool regular; 9812 9813 PetscFunctionBegin; 9814 PetscCall(DMGetFullDM(dmc, &dmco)); 9815 PetscCall(DMGetFullDM(dmf, &dmfo)); 9816 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9817 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9818 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9819 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9820 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9821 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9822 PetscCall(VecSet(cglobalo, 0.)); 9823 PetscCall(VecSet(clocal, 0.)); 9824 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9825 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9826 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9827 PetscCall(VecSet(fglobal, 0.)); 9828 PetscCall(VecSet(fglobalo, 0.)); 9829 PetscCall(VecSet(flocal, 0.)); 9830 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9831 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9832 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9833 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9834 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9835 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9836 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9837 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9838 *shift = fglobal; 9839 PetscCall(VecDestroy(&flocal)); 9840 PetscCall(VecDestroy(&fglobalo)); 9841 PetscCall(VecDestroy(&clocal)); 9842 PetscCall(VecDestroy(&cglobalo)); 9843 PetscCall(VecDestroy(&rscale)); 9844 PetscCall(MatDestroy(&interpo)); 9845 PetscCall(DMDestroy(&dmfo)); 9846 PetscCall(DMDestroy(&dmco)); 9847 PetscFunctionReturn(PETSC_SUCCESS); 9848 } 9849 9850 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9851 { 9852 PetscObject shifto; 9853 Vec shift; 9854 9855 PetscFunctionBegin; 9856 if (!interp) { 9857 Vec rscale; 9858 9859 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9860 PetscCall(VecDestroy(&rscale)); 9861 } else { 9862 PetscCall(PetscObjectReference((PetscObject)interp)); 9863 } 9864 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9865 if (!shifto) { 9866 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9867 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9868 shifto = (PetscObject)shift; 9869 PetscCall(VecDestroy(&shift)); 9870 } 9871 shift = (Vec)shifto; 9872 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9873 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9874 PetscCall(MatDestroy(&interp)); 9875 PetscFunctionReturn(PETSC_SUCCESS); 9876 } 9877 9878 /* Pointwise interpolation 9879 Just code FEM for now 9880 u^f = I u^c 9881 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9882 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9883 I_{ij} = psi^f_i phi^c_j 9884 */ 9885 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9886 { 9887 PetscSection gsc, gsf; 9888 PetscInt m, n; 9889 void *ctx; 9890 DM cdm; 9891 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9892 9893 PetscFunctionBegin; 9894 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9895 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9896 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9897 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9898 9899 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9900 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9901 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9902 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9903 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9904 9905 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9906 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9907 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9908 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9909 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9910 if (scaling) { 9911 /* Use naive scaling */ 9912 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9913 } 9914 PetscFunctionReturn(PETSC_SUCCESS); 9915 } 9916 9917 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9918 { 9919 VecScatter ctx; 9920 9921 PetscFunctionBegin; 9922 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9923 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9924 PetscCall(VecScatterDestroy(&ctx)); 9925 PetscFunctionReturn(PETSC_SUCCESS); 9926 } 9927 9928 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[]) 9929 { 9930 const PetscInt Nc = uOff[1] - uOff[0]; 9931 PetscInt c; 9932 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9933 } 9934 9935 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9936 { 9937 DM dmc; 9938 PetscDS ds; 9939 Vec ones, locmass; 9940 IS cellIS; 9941 PetscFormKey key; 9942 PetscInt depth; 9943 9944 PetscFunctionBegin; 9945 PetscCall(DMClone(dm, &dmc)); 9946 PetscCall(DMCopyDisc(dm, dmc)); 9947 PetscCall(DMGetDS(dmc, &ds)); 9948 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9949 PetscCall(DMCreateGlobalVector(dmc, mass)); 9950 PetscCall(DMGetLocalVector(dmc, &ones)); 9951 PetscCall(DMGetLocalVector(dmc, &locmass)); 9952 PetscCall(DMPlexGetDepth(dmc, &depth)); 9953 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9954 PetscCall(VecSet(locmass, 0.0)); 9955 PetscCall(VecSet(ones, 1.0)); 9956 key.label = NULL; 9957 key.value = 0; 9958 key.field = 0; 9959 key.part = 0; 9960 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9961 PetscCall(ISDestroy(&cellIS)); 9962 PetscCall(VecSet(*mass, 0.0)); 9963 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9964 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9965 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9966 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9967 PetscCall(DMDestroy(&dmc)); 9968 PetscFunctionReturn(PETSC_SUCCESS); 9969 } 9970 9971 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9972 { 9973 PetscSection gsc, gsf; 9974 PetscInt m, n; 9975 void *ctx; 9976 DM cdm; 9977 PetscBool regular; 9978 9979 PetscFunctionBegin; 9980 if (dmFine == dmCoarse) { 9981 DM dmc; 9982 PetscDS ds; 9983 PetscWeakForm wf; 9984 Vec u; 9985 IS cellIS; 9986 PetscFormKey key; 9987 PetscInt depth; 9988 9989 PetscCall(DMClone(dmFine, &dmc)); 9990 PetscCall(DMCopyDisc(dmFine, dmc)); 9991 PetscCall(DMGetDS(dmc, &ds)); 9992 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9993 PetscCall(PetscWeakFormClear(wf)); 9994 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9995 PetscCall(DMCreateMatrix(dmc, mass)); 9996 PetscCall(DMGetLocalVector(dmc, &u)); 9997 PetscCall(DMPlexGetDepth(dmc, &depth)); 9998 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9999 PetscCall(MatZeroEntries(*mass)); 10000 key.label = NULL; 10001 key.value = 0; 10002 key.field = 0; 10003 key.part = 0; 10004 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10005 PetscCall(ISDestroy(&cellIS)); 10006 PetscCall(DMRestoreLocalVector(dmc, &u)); 10007 PetscCall(DMDestroy(&dmc)); 10008 } else { 10009 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10010 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10011 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10012 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10013 10014 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10015 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10016 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10017 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10018 10019 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10020 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10021 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10022 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10023 } 10024 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10025 PetscFunctionReturn(PETSC_SUCCESS); 10026 } 10027 10028 /*@ 10029 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10030 10031 Input Parameter: 10032 . dm - The `DMPLEX` object 10033 10034 Output Parameter: 10035 . regular - The flag 10036 10037 Level: intermediate 10038 10039 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10040 @*/ 10041 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10042 { 10043 PetscFunctionBegin; 10044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10045 PetscAssertPointer(regular, 2); 10046 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10047 PetscFunctionReturn(PETSC_SUCCESS); 10048 } 10049 10050 /*@ 10051 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10052 10053 Input Parameters: 10054 + dm - The `DMPLEX` object 10055 - regular - The flag 10056 10057 Level: intermediate 10058 10059 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10060 @*/ 10061 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10062 { 10063 PetscFunctionBegin; 10064 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10065 ((DM_Plex *)dm->data)->regularRefinement = regular; 10066 PetscFunctionReturn(PETSC_SUCCESS); 10067 } 10068 10069 /*@ 10070 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10071 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10072 10073 Not Collective 10074 10075 Input Parameter: 10076 . dm - The `DMPLEX` object 10077 10078 Output Parameters: 10079 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10080 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10081 10082 Level: intermediate 10083 10084 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10085 @*/ 10086 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10087 { 10088 DM_Plex *plex = (DM_Plex *)dm->data; 10089 10090 PetscFunctionBegin; 10091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10092 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10093 if (anchorSection) *anchorSection = plex->anchorSection; 10094 if (anchorIS) *anchorIS = plex->anchorIS; 10095 PetscFunctionReturn(PETSC_SUCCESS); 10096 } 10097 10098 /*@ 10099 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10100 10101 Collective 10102 10103 Input Parameters: 10104 + dm - The `DMPLEX` object 10105 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10106 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10107 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10108 10109 Level: intermediate 10110 10111 Notes: 10112 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10113 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10114 combination of other points' degrees of freedom. 10115 10116 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10117 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10118 10119 The reference counts of `anchorSection` and `anchorIS` are incremented. 10120 10121 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10122 @*/ 10123 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10124 { 10125 DM_Plex *plex = (DM_Plex *)dm->data; 10126 PetscMPIInt result; 10127 10128 PetscFunctionBegin; 10129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10130 if (anchorSection) { 10131 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10132 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10133 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10134 } 10135 if (anchorIS) { 10136 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10137 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10138 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10139 } 10140 10141 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10142 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10143 plex->anchorSection = anchorSection; 10144 10145 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10146 PetscCall(ISDestroy(&plex->anchorIS)); 10147 plex->anchorIS = anchorIS; 10148 10149 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10150 PetscInt size, a, pStart, pEnd; 10151 const PetscInt *anchors; 10152 10153 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10154 PetscCall(ISGetLocalSize(anchorIS, &size)); 10155 PetscCall(ISGetIndices(anchorIS, &anchors)); 10156 for (a = 0; a < size; a++) { 10157 PetscInt p; 10158 10159 p = anchors[a]; 10160 if (p >= pStart && p < pEnd) { 10161 PetscInt dof; 10162 10163 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10164 if (dof) { 10165 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10166 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10167 } 10168 } 10169 } 10170 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10171 } 10172 /* reset the generic constraints */ 10173 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10174 PetscFunctionReturn(PETSC_SUCCESS); 10175 } 10176 10177 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10178 { 10179 PetscSection anchorSection; 10180 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10181 10182 PetscFunctionBegin; 10183 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10184 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10185 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10186 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10187 if (numFields) { 10188 PetscInt f; 10189 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10190 10191 for (f = 0; f < numFields; f++) { 10192 PetscInt numComp; 10193 10194 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10195 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10196 } 10197 } 10198 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10199 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10200 pStart = PetscMax(pStart, sStart); 10201 pEnd = PetscMin(pEnd, sEnd); 10202 pEnd = PetscMax(pStart, pEnd); 10203 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10204 for (p = pStart; p < pEnd; p++) { 10205 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10206 if (dof) { 10207 PetscCall(PetscSectionGetDof(section, p, &dof)); 10208 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10209 for (f = 0; f < numFields; f++) { 10210 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10211 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10212 } 10213 } 10214 } 10215 PetscCall(PetscSectionSetUp(*cSec)); 10216 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10217 PetscFunctionReturn(PETSC_SUCCESS); 10218 } 10219 10220 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10221 { 10222 PetscSection aSec; 10223 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10224 const PetscInt *anchors; 10225 PetscInt numFields, f; 10226 IS aIS; 10227 MatType mtype; 10228 PetscBool iscuda, iskokkos; 10229 10230 PetscFunctionBegin; 10231 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10232 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10233 PetscCall(PetscSectionGetStorageSize(section, &n)); 10234 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10235 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10236 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10237 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10238 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10239 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10240 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10241 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10242 else mtype = MATSEQAIJ; 10243 PetscCall(MatSetType(*cMat, mtype)); 10244 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10245 PetscCall(ISGetIndices(aIS, &anchors)); 10246 /* cSec will be a subset of aSec and section */ 10247 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10248 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10249 PetscCall(PetscMalloc1(m + 1, &i)); 10250 i[0] = 0; 10251 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10252 for (p = pStart; p < pEnd; p++) { 10253 PetscInt rDof, rOff, r; 10254 10255 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10256 if (!rDof) continue; 10257 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10258 if (numFields) { 10259 for (f = 0; f < numFields; f++) { 10260 annz = 0; 10261 for (r = 0; r < rDof; r++) { 10262 a = anchors[rOff + r]; 10263 if (a < sStart || a >= sEnd) continue; 10264 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10265 annz += aDof; 10266 } 10267 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10268 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10269 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10270 } 10271 } else { 10272 annz = 0; 10273 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10274 for (q = 0; q < dof; q++) { 10275 a = anchors[rOff + q]; 10276 if (a < sStart || a >= sEnd) continue; 10277 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10278 annz += aDof; 10279 } 10280 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10281 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10282 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10283 } 10284 } 10285 nnz = i[m]; 10286 PetscCall(PetscMalloc1(nnz, &j)); 10287 offset = 0; 10288 for (p = pStart; p < pEnd; p++) { 10289 if (numFields) { 10290 for (f = 0; f < numFields; f++) { 10291 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10292 for (q = 0; q < dof; q++) { 10293 PetscInt rDof, rOff, r; 10294 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10295 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10296 for (r = 0; r < rDof; r++) { 10297 PetscInt s; 10298 10299 a = anchors[rOff + r]; 10300 if (a < sStart || a >= sEnd) continue; 10301 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10302 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10303 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10304 } 10305 } 10306 } 10307 } else { 10308 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10309 for (q = 0; q < dof; q++) { 10310 PetscInt rDof, rOff, r; 10311 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10312 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10313 for (r = 0; r < rDof; r++) { 10314 PetscInt s; 10315 10316 a = anchors[rOff + r]; 10317 if (a < sStart || a >= sEnd) continue; 10318 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10319 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10320 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10321 } 10322 } 10323 } 10324 } 10325 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10326 PetscCall(PetscFree(i)); 10327 PetscCall(PetscFree(j)); 10328 PetscCall(ISRestoreIndices(aIS, &anchors)); 10329 PetscFunctionReturn(PETSC_SUCCESS); 10330 } 10331 10332 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10333 { 10334 DM_Plex *plex = (DM_Plex *)dm->data; 10335 PetscSection anchorSection, section, cSec; 10336 Mat cMat; 10337 10338 PetscFunctionBegin; 10339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10340 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10341 if (anchorSection) { 10342 PetscInt Nf; 10343 10344 PetscCall(DMGetLocalSection(dm, §ion)); 10345 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10346 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10347 PetscCall(DMGetNumFields(dm, &Nf)); 10348 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10349 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10350 PetscCall(PetscSectionDestroy(&cSec)); 10351 PetscCall(MatDestroy(&cMat)); 10352 } 10353 PetscFunctionReturn(PETSC_SUCCESS); 10354 } 10355 10356 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10357 { 10358 IS subis; 10359 PetscSection section, subsection; 10360 10361 PetscFunctionBegin; 10362 PetscCall(DMGetLocalSection(dm, §ion)); 10363 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10364 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10365 /* Create subdomain */ 10366 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10367 /* Create submodel */ 10368 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10369 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10370 PetscCall(DMSetLocalSection(*subdm, subsection)); 10371 PetscCall(PetscSectionDestroy(&subsection)); 10372 PetscCall(DMCopyDisc(dm, *subdm)); 10373 /* Create map from submodel to global model */ 10374 if (is) { 10375 PetscSection sectionGlobal, subsectionGlobal; 10376 IS spIS; 10377 const PetscInt *spmap; 10378 PetscInt *subIndices; 10379 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10380 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10381 10382 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10383 PetscCall(ISGetIndices(spIS, &spmap)); 10384 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10385 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10386 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10387 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10388 for (p = pStart; p < pEnd; ++p) { 10389 PetscInt gdof, pSubSize = 0; 10390 10391 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10392 if (gdof > 0) { 10393 for (f = 0; f < Nf; ++f) { 10394 PetscInt fdof, fcdof; 10395 10396 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10397 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10398 pSubSize += fdof - fcdof; 10399 } 10400 subSize += pSubSize; 10401 if (pSubSize) { 10402 if (bs < 0) { 10403 bs = pSubSize; 10404 } else if (bs != pSubSize) { 10405 /* Layout does not admit a pointwise block size */ 10406 bs = 1; 10407 } 10408 } 10409 } 10410 } 10411 /* Must have same blocksize on all procs (some might have no points) */ 10412 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10413 bsLocal[1] = bs; 10414 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10415 if (bsMinMax[0] != bsMinMax[1]) { 10416 bs = 1; 10417 } else { 10418 bs = bsMinMax[0]; 10419 } 10420 PetscCall(PetscMalloc1(subSize, &subIndices)); 10421 for (p = pStart; p < pEnd; ++p) { 10422 PetscInt gdof, goff; 10423 10424 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10425 if (gdof > 0) { 10426 const PetscInt point = spmap[p]; 10427 10428 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10429 for (f = 0; f < Nf; ++f) { 10430 PetscInt fdof, fcdof, fc, f2, poff = 0; 10431 10432 /* Can get rid of this loop by storing field information in the global section */ 10433 for (f2 = 0; f2 < f; ++f2) { 10434 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10435 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10436 poff += fdof - fcdof; 10437 } 10438 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10439 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10440 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10441 } 10442 } 10443 } 10444 PetscCall(ISRestoreIndices(spIS, &spmap)); 10445 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10446 if (bs > 1) { 10447 /* We need to check that the block size does not come from non-contiguous fields */ 10448 PetscInt i, j, set = 1; 10449 for (i = 0; i < subSize; i += bs) { 10450 for (j = 0; j < bs; ++j) { 10451 if (subIndices[i + j] != subIndices[i] + j) { 10452 set = 0; 10453 break; 10454 } 10455 } 10456 } 10457 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10458 } 10459 /* Attach nullspace */ 10460 for (f = 0; f < Nf; ++f) { 10461 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10462 if ((*subdm)->nullspaceConstructors[f]) break; 10463 } 10464 if (f < Nf) { 10465 MatNullSpace nullSpace; 10466 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10467 10468 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10469 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10470 } 10471 } 10472 PetscFunctionReturn(PETSC_SUCCESS); 10473 } 10474 10475 /*@ 10476 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10477 10478 Input Parameters: 10479 + dm - The `DM` 10480 - dummy - unused argument 10481 10482 Options Database Key: 10483 . -dm_plex_monitor_throughput - Activate the monitor 10484 10485 Level: developer 10486 10487 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10488 @*/ 10489 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10490 { 10491 PetscLogHandler default_handler; 10492 10493 PetscFunctionBegin; 10494 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10495 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10496 if (default_handler) { 10497 PetscLogEvent event; 10498 PetscEventPerfInfo eventInfo; 10499 PetscReal cellRate, flopRate; 10500 PetscInt cStart, cEnd, Nf, N; 10501 const char *name; 10502 10503 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10504 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10505 PetscCall(DMGetNumFields(dm, &Nf)); 10506 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10507 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10508 N = (cEnd - cStart) * Nf * eventInfo.count; 10509 flopRate = eventInfo.flops / eventInfo.time; 10510 cellRate = N / eventInfo.time; 10511 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))); 10512 } else { 10513 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."); 10514 } 10515 PetscFunctionReturn(PETSC_SUCCESS); 10516 } 10517