1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 15 16 PetscBool Plexcite = PETSC_FALSE; 17 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 18 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 19 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 20 "journal = {SIAM Journal on Scientific Computing},\n" 21 "volume = {38},\n" 22 "number = {5},\n" 23 "pages = {S143--S155},\n" 24 "eprint = {http://arxiv.org/abs/1506.07749},\n" 25 "doi = {10.1137/15M1026092},\n" 26 "year = {2016},\n" 27 "petsc_uses={DMPlex},\n}\n"; 28 29 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 30 31 /*@ 32 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 33 34 Input Parameter: 35 . dm - The `DMPLEX` object 36 37 Output Parameter: 38 . simplex - Flag checking for a simplex 39 40 Level: intermediate 41 42 Note: 43 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 44 If the mesh has no cells, this returns `PETSC_FALSE`. 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 47 @*/ 48 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 49 { 50 DMPolytopeType ct; 51 PetscInt cStart, cEnd; 52 53 PetscFunctionBegin; 54 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 55 if (cEnd <= cStart) { 56 *simplex = PETSC_FALSE; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 60 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@ 65 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 66 67 Input Parameters: 68 + dm - The `DMPLEX` object 69 - height - The cell height in the Plex, 0 is the default 70 71 Output Parameters: 72 + cStart - The first "normal" cell 73 - cEnd - The upper bound on "normal" cells 74 75 Level: developer 76 77 Note: 78 This function requires that tensor cells are ordered last. 79 80 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 81 @*/ 82 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 83 { 84 DMLabel ctLabel; 85 IS valueIS; 86 const PetscInt *ctypes; 87 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 88 89 PetscFunctionBegin; 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 92 PetscCall(ISGetLocalSize(valueIS, &Nct)); 93 PetscCall(ISGetIndices(valueIS, &ctypes)); 94 if (!Nct) cS = cE = 0; 95 for (PetscInt t = 0; t < Nct; ++t) { 96 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 97 PetscInt ctS, ctE, ht; 98 99 if (ct == DM_POLYTOPE_UNKNOWN) { 100 // If any cells are not typed, just use all cells 101 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 102 break; 103 } 104 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 105 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 106 if (ctS >= ctE) continue; 107 // Check that a point has the right height 108 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 109 if (ht != height) continue; 110 cS = PetscMin(cS, ctS); 111 cE = PetscMax(cE, ctE); 112 } 113 PetscCall(ISDestroy(&valueIS)); 114 // Reset label for fast lookup 115 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 116 if (cStart) *cStart = cS; 117 if (cEnd) *cEnd = cE; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 122 { 123 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 124 PetscInt *sStart, *sEnd; 125 PetscViewerVTKFieldType *ft; 126 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 127 DMLabel depthLabel, ctLabel; 128 129 PetscFunctionBegin; 130 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 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 162 } 163 164 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 165 *types = 0; 166 167 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 168 if (globalvcdof[c]) ++(*types); 169 } 170 171 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 172 t = 0; 173 if (globalvcdof[DM_NUM_POLYTOPES]) { 174 sStart[t] = vStart; 175 sEnd[t] = vEnd; 176 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 177 ++t; 178 } 179 180 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 181 if (globalvcdof[c]) { 182 const DMPolytopeType ict = (DMPolytopeType)c; 183 184 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 185 sStart[t] = cStart; 186 sEnd[t] = cEnd; 187 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 188 ++t; 189 } 190 } 191 192 if (!(*types)) { 193 if (field >= 0) { 194 const char *fieldname; 195 196 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 197 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 198 } else { 199 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 200 } 201 } 202 203 *ssStart = sStart; 204 *ssEnd = sEnd; 205 *sft = ft; 206 PetscFunctionReturn(PETSC_SUCCESS); 207 } 208 209 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 210 { 211 PetscFunctionBegin; 212 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 213 PetscFunctionReturn(PETSC_SUCCESS); 214 } 215 216 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 217 { 218 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 219 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 220 221 PetscFunctionBegin; 222 *ft = PETSC_VTK_INVALID; 223 PetscCall(DMGetCoordinateDim(dm, &cdim)); 224 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 225 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 226 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 227 if (field >= 0) { 228 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 229 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 230 } else { 231 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 232 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 233 } 234 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 235 if (globalvcdof[0]) { 236 *sStart = vStart; 237 *sEnd = vEnd; 238 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 239 else *ft = PETSC_VTK_POINT_FIELD; 240 } else if (globalvcdof[1]) { 241 *sStart = cStart; 242 *sEnd = cEnd; 243 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 244 else *ft = PETSC_VTK_CELL_FIELD; 245 } else { 246 if (field >= 0) { 247 const char *fieldname; 248 249 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 250 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 251 } else { 252 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 253 } 254 } 255 PetscFunctionReturn(PETSC_SUCCESS); 256 } 257 258 /*@ 259 DMPlexVecView1D - Plot many 1D solutions on the same line graph 260 261 Collective 262 263 Input Parameters: 264 + dm - The `DMPLEX` object 265 . n - The number of vectors 266 . u - The array of local vectors 267 - viewer - The `PetscViewer` 268 269 Level: advanced 270 271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 272 @*/ 273 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 274 { 275 PetscDS ds; 276 PetscDraw draw = NULL; 277 PetscDrawLG lg; 278 Vec coordinates; 279 const PetscScalar *coords, **sol; 280 PetscReal *vals; 281 PetscInt *Nc; 282 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 283 char **names; 284 285 PetscFunctionBegin; 286 PetscCall(DMGetDS(dm, &ds)); 287 PetscCall(PetscDSGetNumFields(ds, &Nf)); 288 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 289 PetscCall(PetscDSGetComponents(ds, &Nc)); 290 291 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 292 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 293 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 294 295 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 296 for (i = 0, l = 0; i < n; ++i) { 297 const char *vname; 298 299 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 300 for (f = 0; f < Nf; ++f) { 301 PetscObject disc; 302 const char *fname; 303 char tmpname[PETSC_MAX_PATH_LEN]; 304 305 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 306 /* TODO Create names for components */ 307 for (c = 0; c < Nc[f]; ++c, ++l) { 308 PetscCall(PetscObjectGetName(disc, &fname)); 309 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 312 PetscCall(PetscStrallocpy(tmpname, &names[l])); 313 } 314 } 315 } 316 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 317 /* Just add P_1 support for now */ 318 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 319 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 320 PetscCall(VecGetArrayRead(coordinates, &coords)); 321 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 322 for (v = vStart; v < vEnd; ++v) { 323 PetscScalar *x, *svals; 324 325 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 326 for (i = 0; i < n; ++i) { 327 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 328 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 329 } 330 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 331 } 332 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 333 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 334 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 335 PetscCall(PetscFree3(sol, names, vals)); 336 337 PetscCall(PetscDrawLGDraw(lg)); 338 PetscCall(PetscDrawLGDestroy(&lg)); 339 PetscFunctionReturn(PETSC_SUCCESS); 340 } 341 342 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 343 { 344 DM dm; 345 346 PetscFunctionBegin; 347 PetscCall(VecGetDM(u, &dm)); 348 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 349 PetscFunctionReturn(PETSC_SUCCESS); 350 } 351 352 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 353 { 354 DM dm; 355 PetscSection s; 356 PetscDraw draw, popup; 357 DM cdm; 358 PetscSection coordSection; 359 Vec coordinates; 360 const PetscScalar *array; 361 PetscReal lbound[3], ubound[3]; 362 PetscReal vbound[2], time; 363 PetscBool flg; 364 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 365 const char *name; 366 char title[PETSC_MAX_PATH_LEN]; 367 368 PetscFunctionBegin; 369 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 370 PetscCall(VecGetDM(v, &dm)); 371 PetscCall(DMGetCoordinateDim(dm, &dim)); 372 PetscCall(DMGetLocalSection(dm, &s)); 373 PetscCall(PetscSectionGetNumFields(s, &Nf)); 374 PetscCall(DMGetCoarsenLevel(dm, &level)); 375 PetscCall(DMGetCoordinateDM(dm, &cdm)); 376 PetscCall(DMGetLocalSection(cdm, &coordSection)); 377 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 378 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 379 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 380 381 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 382 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 383 384 PetscCall(VecGetLocalSize(coordinates, &N)); 385 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 386 PetscCall(PetscDrawClear(draw)); 387 388 /* Could implement something like DMDASelectFields() */ 389 for (f = 0; f < Nf; ++f) { 390 DM fdm = dm; 391 Vec fv = v; 392 IS fis; 393 char prefix[PETSC_MAX_PATH_LEN]; 394 const char *fname; 395 396 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 397 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 398 399 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 400 else prefix[0] = '\0'; 401 if (Nf > 1) { 402 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 403 PetscCall(VecGetSubVector(v, fis, &fv)); 404 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 405 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 406 } 407 for (comp = 0; comp < Nc; ++comp, ++w) { 408 PetscInt nmax = 2; 409 410 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 411 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 412 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 413 PetscCall(PetscDrawSetTitle(draw, title)); 414 415 /* TODO Get max and min only for this component */ 416 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 417 if (!flg) { 418 PetscCall(VecMin(fv, NULL, &vbound[0])); 419 PetscCall(VecMax(fv, NULL, &vbound[1])); 420 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 421 } 422 423 PetscCall(PetscDrawGetPopup(draw, &popup)); 424 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 425 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 426 PetscCall(VecGetArrayRead(fv, &array)); 427 for (c = cStart; c < cEnd; ++c) { 428 PetscScalar *coords = NULL, *a = NULL; 429 const PetscScalar *coords_arr; 430 PetscBool isDG; 431 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 432 433 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 434 if (a) { 435 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 436 color[1] = color[2] = color[3] = color[0]; 437 } else { 438 PetscScalar *vals = NULL; 439 PetscInt numVals, va; 440 441 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 442 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); 443 switch (numVals / Nc) { 444 case 3: /* P1 Triangle */ 445 case 4: /* P1 Quadrangle */ 446 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 447 break; 448 case 6: /* P2 Triangle */ 449 case 8: /* P2 Quadrangle */ 450 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 451 break; 452 default: 453 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 454 } 455 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 456 } 457 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 458 switch (numCoords) { 459 case 6: 460 case 12: /* Localized triangle */ 461 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])); 462 break; 463 case 8: 464 case 16: /* Localized quadrilateral */ 465 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])); 466 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])); 467 break; 468 default: 469 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 470 } 471 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 472 } 473 PetscCall(VecRestoreArrayRead(fv, &array)); 474 PetscCall(PetscDrawFlush(draw)); 475 PetscCall(PetscDrawPause(draw)); 476 PetscCall(PetscDrawSave(draw)); 477 } 478 if (Nf > 1) { 479 PetscCall(VecRestoreSubVector(v, fis, &fv)); 480 PetscCall(ISDestroy(&fis)); 481 PetscCall(DMDestroy(&fdm)); 482 } 483 } 484 PetscFunctionReturn(PETSC_SUCCESS); 485 } 486 487 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 488 { 489 DM dm; 490 PetscDraw draw; 491 PetscInt dim; 492 PetscBool isnull; 493 494 PetscFunctionBegin; 495 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 496 PetscCall(PetscDrawIsNull(draw, &isnull)); 497 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 498 499 PetscCall(VecGetDM(v, &dm)); 500 PetscCall(DMGetCoordinateDim(dm, &dim)); 501 switch (dim) { 502 case 1: 503 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 504 break; 505 case 2: 506 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 507 break; 508 default: 509 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 510 } 511 PetscFunctionReturn(PETSC_SUCCESS); 512 } 513 514 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 515 { 516 DM dm; 517 Vec locv; 518 const char *name; 519 PetscSection section; 520 PetscInt pStart, pEnd; 521 PetscInt numFields; 522 PetscViewerVTKFieldType ft; 523 524 PetscFunctionBegin; 525 PetscCall(VecGetDM(v, &dm)); 526 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 527 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 528 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 529 PetscCall(VecCopy(v, locv)); 530 PetscCall(DMGetLocalSection(dm, §ion)); 531 PetscCall(PetscSectionGetNumFields(section, &numFields)); 532 if (!numFields) { 533 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 534 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 535 } else { 536 PetscInt f; 537 538 for (f = 0; f < numFields; f++) { 539 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 540 if (ft == PETSC_VTK_INVALID) continue; 541 PetscCall(PetscObjectReference((PetscObject)locv)); 542 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 543 } 544 PetscCall(VecDestroy(&locv)); 545 } 546 PetscFunctionReturn(PETSC_SUCCESS); 547 } 548 549 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 550 { 551 DM dm; 552 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 553 554 PetscFunctionBegin; 555 PetscCall(VecGetDM(v, &dm)); 556 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 562 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 563 PetscInt i, numFields; 564 PetscObject fe; 565 PetscBool fem = PETSC_FALSE; 566 Vec locv = v; 567 const char *name; 568 PetscInt step; 569 PetscReal time; 570 571 PetscCall(DMGetNumFields(dm, &numFields)); 572 for (i = 0; i < numFields; i++) { 573 PetscCall(DMGetField(dm, i, NULL, &fe)); 574 if (fe->classid == PETSCFE_CLASSID) { 575 fem = PETSC_TRUE; 576 break; 577 } 578 } 579 if (fem) { 580 PetscObject isZero; 581 582 PetscCall(DMGetLocalVector(dm, &locv)); 583 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 584 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 585 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 586 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 587 PetscCall(VecCopy(v, locv)); 588 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 589 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 590 } 591 if (isvtk) { 592 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 593 } else if (ishdf5) { 594 #if defined(PETSC_HAVE_HDF5) 595 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 596 #else 597 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 598 #endif 599 } else if (isdraw) { 600 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 601 } else if (isglvis) { 602 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 603 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 604 PetscCall(VecView_GLVis(locv, viewer)); 605 } else if (iscgns) { 606 #if defined(PETSC_HAVE_CGNS) 607 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 608 #else 609 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 610 #endif 611 } 612 if (fem) { 613 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 614 PetscCall(DMRestoreLocalVector(dm, &locv)); 615 } 616 } else { 617 PetscBool isseq; 618 619 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 620 if (isseq) PetscCall(VecView_Seq(v, viewer)); 621 else PetscCall(VecView_MPI(v, viewer)); 622 } 623 PetscFunctionReturn(PETSC_SUCCESS); 624 } 625 626 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 627 { 628 DM dm; 629 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 630 631 PetscFunctionBegin; 632 PetscCall(VecGetDM(v, &dm)); 633 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (isvtk || isdraw || isglvis || iscgns) { 641 Vec locv; 642 PetscObject isZero; 643 const char *name; 644 645 PetscCall(DMGetLocalVector(dm, &locv)); 646 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 647 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 648 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 649 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 650 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 651 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 652 PetscCall(VecView_Plex_Local(locv, viewer)); 653 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 654 PetscCall(DMRestoreLocalVector(dm, &locv)); 655 } else if (ishdf5) { 656 #if defined(PETSC_HAVE_HDF5) 657 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 658 #else 659 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 660 #endif 661 } else if (isexodusii) { 662 #if defined(PETSC_HAVE_EXODUSII) 663 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 664 #else 665 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 666 #endif 667 } else { 668 PetscBool isseq; 669 670 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 671 if (isseq) PetscCall(VecView_Seq(v, viewer)); 672 else PetscCall(VecView_MPI(v, viewer)); 673 } 674 PetscFunctionReturn(PETSC_SUCCESS); 675 } 676 677 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 678 { 679 DM dm; 680 MPI_Comm comm; 681 PetscViewerFormat format; 682 Vec v; 683 PetscBool isvtk, ishdf5; 684 685 PetscFunctionBegin; 686 PetscCall(VecGetDM(originalv, &dm)); 687 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 688 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 689 PetscCall(PetscViewerGetFormat(viewer, &format)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 692 if (format == PETSC_VIEWER_NATIVE) { 693 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 694 /* this need a better fix */ 695 if (dm->useNatural) { 696 if (dm->sfNatural) { 697 const char *vecname; 698 PetscInt n, nroots; 699 700 PetscCall(VecGetLocalSize(originalv, &n)); 701 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 702 if (n == nroots) { 703 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 704 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 705 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 706 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 707 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 709 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 710 } else v = originalv; 711 } else v = originalv; 712 713 if (ishdf5) { 714 #if defined(PETSC_HAVE_HDF5) 715 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 716 #else 717 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 718 #endif 719 } else if (isvtk) { 720 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 721 } else { 722 PetscBool isseq; 723 724 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 725 if (isseq) PetscCall(VecView_Seq(v, viewer)); 726 else PetscCall(VecView_MPI(v, viewer)); 727 } 728 if (v != originalv) PetscCall(VecDestroy(&v)); 729 PetscFunctionReturn(PETSC_SUCCESS); 730 } 731 732 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 733 { 734 DM dm; 735 PetscBool ishdf5; 736 737 PetscFunctionBegin; 738 PetscCall(VecGetDM(v, &dm)); 739 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 740 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 741 if (ishdf5) { 742 DM dmBC; 743 Vec gv; 744 const char *name; 745 746 PetscCall(DMGetOutputDM(dm, &dmBC)); 747 PetscCall(DMGetGlobalVector(dmBC, &gv)); 748 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 749 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 750 PetscCall(VecLoad_Default(gv, viewer)); 751 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 753 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 754 } else PetscCall(VecLoad_Default(v, viewer)); 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 759 { 760 DM dm; 761 PetscBool ishdf5, isexodusii; 762 763 PetscFunctionBegin; 764 PetscCall(VecGetDM(v, &dm)); 765 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 768 if (ishdf5) { 769 #if defined(PETSC_HAVE_HDF5) 770 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 771 #else 772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 773 #endif 774 } else if (isexodusii) { 775 #if defined(PETSC_HAVE_EXODUSII) 776 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 777 #else 778 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 779 #endif 780 } else PetscCall(VecLoad_Default(v, viewer)); 781 PetscFunctionReturn(PETSC_SUCCESS); 782 } 783 784 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 785 { 786 DM dm; 787 PetscViewerFormat format; 788 PetscBool ishdf5; 789 790 PetscFunctionBegin; 791 PetscCall(VecGetDM(originalv, &dm)); 792 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 793 PetscCall(PetscViewerGetFormat(viewer, &format)); 794 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 795 if (format == PETSC_VIEWER_NATIVE) { 796 if (dm->useNatural) { 797 if (dm->sfNatural) { 798 if (ishdf5) { 799 #if defined(PETSC_HAVE_HDF5) 800 Vec v; 801 const char *vecname; 802 803 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 804 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 805 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 806 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 807 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 808 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 809 PetscCall(VecDestroy(&v)); 810 #else 811 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 812 #endif 813 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 814 } 815 } else PetscCall(VecLoad_Default(originalv, viewer)); 816 } 817 PetscFunctionReturn(PETSC_SUCCESS); 818 } 819 820 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 821 { 822 PetscSection coordSection; 823 Vec coordinates; 824 DMLabel depthLabel, celltypeLabel; 825 const char *name[4]; 826 const PetscScalar *a; 827 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 828 829 PetscFunctionBegin; 830 PetscCall(DMGetDimension(dm, &dim)); 831 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 832 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 833 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 834 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 835 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 836 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 837 PetscCall(VecGetArrayRead(coordinates, &a)); 838 name[0] = "vertex"; 839 name[1] = "edge"; 840 name[dim - 1] = "face"; 841 name[dim] = "cell"; 842 for (c = cStart; c < cEnd; ++c) { 843 PetscInt *closure = NULL; 844 PetscInt closureSize, cl, ct; 845 846 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 847 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 848 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 849 PetscCall(PetscViewerASCIIPushTab(viewer)); 850 for (cl = 0; cl < closureSize * 2; cl += 2) { 851 PetscInt point = closure[cl], depth, dof, off, d, p; 852 853 if ((point < pStart) || (point >= pEnd)) continue; 854 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 855 if (!dof) continue; 856 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 857 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 859 for (p = 0; p < dof / dim; ++p) { 860 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 861 for (d = 0; d < dim; ++d) { 862 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 863 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 864 } 865 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 866 } 867 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 868 } 869 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 870 PetscCall(PetscViewerASCIIPopTab(viewer)); 871 } 872 PetscCall(VecRestoreArrayRead(coordinates, &a)); 873 PetscFunctionReturn(PETSC_SUCCESS); 874 } 875 876 typedef enum { 877 CS_CARTESIAN, 878 CS_POLAR, 879 CS_CYLINDRICAL, 880 CS_SPHERICAL 881 } CoordSystem; 882 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 883 884 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 885 { 886 PetscInt i; 887 888 PetscFunctionBegin; 889 if (dim > 3) { 890 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 891 } else { 892 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 893 894 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 895 switch (cs) { 896 case CS_CARTESIAN: 897 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 898 break; 899 case CS_POLAR: 900 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 901 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 902 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 903 break; 904 case CS_CYLINDRICAL: 905 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 906 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 907 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 908 trcoords[2] = coords[2]; 909 break; 910 case CS_SPHERICAL: 911 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 912 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 913 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 914 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 915 break; 916 } 917 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 918 } 919 PetscFunctionReturn(PETSC_SUCCESS); 920 } 921 922 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 923 { 924 DM_Plex *mesh = (DM_Plex *)dm->data; 925 DM cdm, cdmCell; 926 PetscSection coordSection, coordSectionCell; 927 Vec coordinates, coordinatesCell; 928 PetscViewerFormat format; 929 930 PetscFunctionBegin; 931 PetscCall(PetscViewerGetFormat(viewer, &format)); 932 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 933 const char *name; 934 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 935 PetscInt pStart, pEnd, p, numLabels, l; 936 PetscMPIInt rank, size; 937 938 PetscCall(DMGetCoordinateDM(dm, &cdm)); 939 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 940 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 941 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 942 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 943 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 944 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 945 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 946 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 947 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 949 PetscCall(DMGetDimension(dm, &dim)); 950 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 951 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 952 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 953 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 955 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 956 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 957 for (p = pStart; p < pEnd; ++p) { 958 PetscInt dof, off, s; 959 960 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 961 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 962 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 963 } 964 PetscCall(PetscViewerFlush(viewer)); 965 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 966 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 967 for (p = pStart; p < pEnd; ++p) { 968 PetscInt dof, off, c; 969 970 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 971 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 972 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])); 973 } 974 PetscCall(PetscViewerFlush(viewer)); 975 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 976 if (coordSection && coordinates) { 977 CoordSystem cs = CS_CARTESIAN; 978 const PetscScalar *array, *arrayCell = NULL; 979 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 980 PetscMPIInt rank; 981 const char *name; 982 983 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 984 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 985 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 986 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 987 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 988 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 989 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 990 pStart = PetscMin(pvStart, pcStart); 991 pEnd = PetscMax(pvEnd, pcEnd); 992 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 994 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 995 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 996 997 PetscCall(VecGetArrayRead(coordinates, &array)); 998 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 999 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1000 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1001 for (p = pStart; p < pEnd; ++p) { 1002 PetscInt dof, off; 1003 1004 if (p >= pvStart && p < pvEnd) { 1005 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1006 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1007 if (dof) { 1008 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1009 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1010 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1011 } 1012 } 1013 if (cdmCell && p >= pcStart && p < pcEnd) { 1014 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1015 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1016 if (dof) { 1017 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1018 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1019 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1020 } 1021 } 1022 } 1023 PetscCall(PetscViewerFlush(viewer)); 1024 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1025 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1026 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1027 } 1028 PetscCall(DMGetNumLabels(dm, &numLabels)); 1029 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1030 for (l = 0; l < numLabels; ++l) { 1031 DMLabel label; 1032 PetscBool isdepth; 1033 const char *name; 1034 1035 PetscCall(DMGetLabelName(dm, l, &name)); 1036 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1037 if (isdepth) continue; 1038 PetscCall(DMGetLabel(dm, name, &label)); 1039 PetscCall(DMLabelView(label, viewer)); 1040 } 1041 if (size > 1) { 1042 PetscSF sf; 1043 1044 PetscCall(DMGetPointSF(dm, &sf)); 1045 PetscCall(PetscSFView(sf, viewer)); 1046 } 1047 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, 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 DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1765 { 1766 DMPolytopeType ct; 1767 PetscReal centroid[2] = {0., 0.}; 1768 PetscMPIInt rank; 1769 PetscInt fillColor, v, e, d; 1770 1771 PetscFunctionBegin; 1772 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1773 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1774 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1775 switch (ct) { 1776 case DM_POLYTOPE_TRIANGLE: { 1777 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1778 1779 for (v = 0; v < 3; ++v) { 1780 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1781 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1782 } 1783 for (e = 0; e < 3; ++e) { 1784 refCoords[0] = refVertices[e * 2 + 0]; 1785 refCoords[1] = refVertices[e * 2 + 1]; 1786 for (d = 1; d <= edgeDiv; ++d) { 1787 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1788 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1789 } 1790 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1791 for (d = 0; d < edgeDiv; ++d) { 1792 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)); 1793 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1794 } 1795 } 1796 } break; 1797 default: 1798 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1799 } 1800 PetscFunctionReturn(PETSC_SUCCESS); 1801 } 1802 1803 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1804 { 1805 PetscDraw draw; 1806 DM cdm; 1807 PetscSection coordSection; 1808 Vec coordinates; 1809 PetscReal xyl[3], xyr[3]; 1810 PetscReal *refCoords, *edgeCoords; 1811 PetscBool isnull, drawAffine = PETSC_TRUE; 1812 PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4; 1813 1814 PetscFunctionBegin; 1815 PetscCall(DMGetCoordinateDim(dm, &dim)); 1816 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1817 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1818 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1819 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1820 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1821 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1822 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1823 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1824 1825 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1826 PetscCall(PetscDrawIsNull(draw, &isnull)); 1827 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1828 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1829 1830 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1831 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1832 PetscCall(PetscDrawClear(draw)); 1833 1834 for (c = cStart; c < cEnd; ++c) { 1835 PetscScalar *coords = NULL; 1836 const PetscScalar *coords_arr; 1837 PetscInt numCoords; 1838 PetscBool isDG; 1839 1840 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1841 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1842 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1843 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1844 } 1845 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1846 PetscCall(PetscDrawFlush(draw)); 1847 PetscCall(PetscDrawPause(draw)); 1848 PetscCall(PetscDrawSave(draw)); 1849 PetscFunctionReturn(PETSC_SUCCESS); 1850 } 1851 1852 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1853 { 1854 DM odm = dm, rdm = dm, cdm; 1855 PetscFE fe; 1856 PetscSpace sp; 1857 PetscClassId id; 1858 PetscInt degree; 1859 PetscBool hoView = PETSC_TRUE; 1860 1861 PetscFunctionBegin; 1862 PetscObjectOptionsBegin((PetscObject)dm); 1863 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1864 PetscOptionsEnd(); 1865 PetscCall(PetscObjectReference((PetscObject)dm)); 1866 *hdm = dm; 1867 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1868 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1869 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1870 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1871 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1872 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1873 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1874 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1875 DM cdm, rcdm; 1876 Mat In; 1877 Vec cl, rcl; 1878 1879 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1880 if (rd > 1) PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1881 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1882 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1883 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1884 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1885 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1886 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1887 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1888 PetscCall(MatMult(In, cl, rcl)); 1889 PetscCall(MatDestroy(&In)); 1890 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1891 PetscCall(DMDestroy(&odm)); 1892 odm = rdm; 1893 } 1894 *hdm = rdm; 1895 PetscFunctionReturn(PETSC_SUCCESS); 1896 } 1897 1898 #if defined(PETSC_HAVE_EXODUSII) 1899 #include <exodusII.h> 1900 #include <petscviewerexodusii.h> 1901 #endif 1902 1903 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1904 { 1905 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1906 char name[PETSC_MAX_PATH_LEN]; 1907 1908 PetscFunctionBegin; 1909 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1910 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1911 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1912 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1913 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1914 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1916 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1917 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1918 if (iascii) { 1919 PetscViewerFormat format; 1920 PetscCall(PetscViewerGetFormat(viewer, &format)); 1921 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1922 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1923 } else if (ishdf5) { 1924 #if defined(PETSC_HAVE_HDF5) 1925 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1926 #else 1927 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1928 #endif 1929 } else if (isvtk) { 1930 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1931 } else if (isdraw) { 1932 DM hdm; 1933 1934 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1935 PetscCall(DMPlexView_Draw(hdm, viewer)); 1936 PetscCall(DMDestroy(&hdm)); 1937 } else if (isglvis) { 1938 PetscCall(DMPlexView_GLVis(dm, viewer)); 1939 #if defined(PETSC_HAVE_EXODUSII) 1940 } else if (isexodus) { 1941 /* 1942 exodusII requires that all sets be part of exactly one cell set. 1943 If the dm does not have a "Cell Sets" label defined, we create one 1944 with ID 1, containing all cells. 1945 Note that if the Cell Sets label is defined but does not cover all cells, 1946 we may still have a problem. This should probably be checked here or in the viewer; 1947 */ 1948 PetscInt numCS; 1949 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1950 if (!numCS) { 1951 PetscInt cStart, cEnd, c; 1952 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1953 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1954 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1955 } 1956 PetscCall(DMView_PlexExodusII(dm, viewer)); 1957 #endif 1958 #if defined(PETSC_HAVE_CGNS) 1959 } else if (iscgns) { 1960 PetscCall(DMView_PlexCGNS(dm, viewer)); 1961 #endif 1962 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1963 /* Optionally view the partition */ 1964 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1965 if (flg) { 1966 Vec ranks; 1967 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1968 PetscCall(VecView(ranks, viewer)); 1969 PetscCall(VecDestroy(&ranks)); 1970 } 1971 /* Optionally view a label */ 1972 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1973 if (flg) { 1974 DMLabel label; 1975 Vec val; 1976 1977 PetscCall(DMGetLabel(dm, name, &label)); 1978 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1979 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1980 PetscCall(VecView(val, viewer)); 1981 PetscCall(VecDestroy(&val)); 1982 } 1983 PetscFunctionReturn(PETSC_SUCCESS); 1984 } 1985 1986 /*@ 1987 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1988 1989 Collective 1990 1991 Input Parameters: 1992 + dm - The `DM` whose topology is to be saved 1993 - viewer - The `PetscViewer` to save it in 1994 1995 Level: advanced 1996 1997 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1998 @*/ 1999 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2000 { 2001 PetscBool ishdf5; 2002 2003 PetscFunctionBegin; 2004 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2005 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2006 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2007 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2008 if (ishdf5) { 2009 #if defined(PETSC_HAVE_HDF5) 2010 PetscViewerFormat format; 2011 PetscCall(PetscViewerGetFormat(viewer, &format)); 2012 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2013 IS globalPointNumbering; 2014 2015 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2016 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2017 PetscCall(ISDestroy(&globalPointNumbering)); 2018 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2019 #else 2020 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2021 #endif 2022 } 2023 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2024 PetscFunctionReturn(PETSC_SUCCESS); 2025 } 2026 2027 /*@ 2028 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2029 2030 Collective 2031 2032 Input Parameters: 2033 + dm - The `DM` whose coordinates are to be saved 2034 - viewer - The `PetscViewer` for saving 2035 2036 Level: advanced 2037 2038 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2039 @*/ 2040 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2041 { 2042 PetscBool ishdf5; 2043 2044 PetscFunctionBegin; 2045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2046 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2047 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2048 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2049 if (ishdf5) { 2050 #if defined(PETSC_HAVE_HDF5) 2051 PetscViewerFormat format; 2052 PetscCall(PetscViewerGetFormat(viewer, &format)); 2053 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2054 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2055 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2056 #else 2057 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2058 #endif 2059 } 2060 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2061 PetscFunctionReturn(PETSC_SUCCESS); 2062 } 2063 2064 /*@ 2065 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2066 2067 Collective 2068 2069 Input Parameters: 2070 + dm - The `DM` whose labels are to be saved 2071 - viewer - The `PetscViewer` for saving 2072 2073 Level: advanced 2074 2075 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2076 @*/ 2077 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2078 { 2079 PetscBool ishdf5; 2080 2081 PetscFunctionBegin; 2082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2083 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2084 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2085 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2086 if (ishdf5) { 2087 #if defined(PETSC_HAVE_HDF5) 2088 IS globalPointNumbering; 2089 PetscViewerFormat format; 2090 2091 PetscCall(PetscViewerGetFormat(viewer, &format)); 2092 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2093 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2094 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2095 PetscCall(ISDestroy(&globalPointNumbering)); 2096 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2097 #else 2098 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2099 #endif 2100 } 2101 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2102 PetscFunctionReturn(PETSC_SUCCESS); 2103 } 2104 2105 /*@ 2106 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2107 2108 Collective 2109 2110 Input Parameters: 2111 + dm - The `DM` that contains the topology on which the section to be saved is defined 2112 . viewer - The `PetscViewer` for saving 2113 - sectiondm - The `DM` that contains the section to be saved 2114 2115 Level: advanced 2116 2117 Notes: 2118 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. 2119 2120 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 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. 2121 2122 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2123 @*/ 2124 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2125 { 2126 PetscBool ishdf5; 2127 2128 PetscFunctionBegin; 2129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2130 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2131 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2132 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2133 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2134 if (ishdf5) { 2135 #if defined(PETSC_HAVE_HDF5) 2136 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2137 #else 2138 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2139 #endif 2140 } 2141 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2142 PetscFunctionReturn(PETSC_SUCCESS); 2143 } 2144 2145 /*@ 2146 DMPlexGlobalVectorView - Saves a global vector 2147 2148 Collective 2149 2150 Input Parameters: 2151 + dm - The `DM` that represents the topology 2152 . viewer - The `PetscViewer` to save data with 2153 . sectiondm - The `DM` that contains the global section on which vec is defined 2154 - vec - The global vector to be saved 2155 2156 Level: advanced 2157 2158 Notes: 2159 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 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. 2160 2161 Calling sequence: 2162 .vb 2163 DMCreate(PETSC_COMM_WORLD, &dm); 2164 DMSetType(dm, DMPLEX); 2165 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2166 DMClone(dm, §iondm); 2167 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2168 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2169 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2170 PetscSectionSetChart(section, pStart, pEnd); 2171 PetscSectionSetUp(section); 2172 DMSetLocalSection(sectiondm, section); 2173 PetscSectionDestroy(§ion); 2174 DMGetGlobalVector(sectiondm, &vec); 2175 PetscObjectSetName((PetscObject)vec, "vec_name"); 2176 DMPlexTopologyView(dm, viewer); 2177 DMPlexSectionView(dm, viewer, sectiondm); 2178 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2179 DMRestoreGlobalVector(sectiondm, &vec); 2180 DMDestroy(§iondm); 2181 DMDestroy(&dm); 2182 .ve 2183 2184 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2185 @*/ 2186 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2187 { 2188 PetscBool ishdf5; 2189 2190 PetscFunctionBegin; 2191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2192 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2193 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2194 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2195 /* Check consistency */ 2196 { 2197 PetscSection section; 2198 PetscBool includesConstraints; 2199 PetscInt m, m1; 2200 2201 PetscCall(VecGetLocalSize(vec, &m1)); 2202 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2203 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2204 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2205 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2206 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2207 } 2208 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2209 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2210 if (ishdf5) { 2211 #if defined(PETSC_HAVE_HDF5) 2212 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2213 #else 2214 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2215 #endif 2216 } 2217 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2218 PetscFunctionReturn(PETSC_SUCCESS); 2219 } 2220 2221 /*@ 2222 DMPlexLocalVectorView - Saves a local vector 2223 2224 Collective 2225 2226 Input Parameters: 2227 + dm - The `DM` that represents the topology 2228 . viewer - The `PetscViewer` to save data with 2229 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2230 - vec - The local vector to be saved 2231 2232 Level: advanced 2233 2234 Note: 2235 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 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. 2236 2237 Calling sequence: 2238 .vb 2239 DMCreate(PETSC_COMM_WORLD, &dm); 2240 DMSetType(dm, DMPLEX); 2241 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2242 DMClone(dm, §iondm); 2243 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2244 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2245 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2246 PetscSectionSetChart(section, pStart, pEnd); 2247 PetscSectionSetUp(section); 2248 DMSetLocalSection(sectiondm, section); 2249 DMGetLocalVector(sectiondm, &vec); 2250 PetscObjectSetName((PetscObject)vec, "vec_name"); 2251 DMPlexTopologyView(dm, viewer); 2252 DMPlexSectionView(dm, viewer, sectiondm); 2253 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2254 DMRestoreLocalVector(sectiondm, &vec); 2255 DMDestroy(§iondm); 2256 DMDestroy(&dm); 2257 .ve 2258 2259 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2260 @*/ 2261 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2262 { 2263 PetscBool ishdf5; 2264 2265 PetscFunctionBegin; 2266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2267 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2268 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2269 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2270 /* Check consistency */ 2271 { 2272 PetscSection section; 2273 PetscBool includesConstraints; 2274 PetscInt m, m1; 2275 2276 PetscCall(VecGetLocalSize(vec, &m1)); 2277 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2278 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2279 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2280 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2281 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2282 } 2283 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2284 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2285 if (ishdf5) { 2286 #if defined(PETSC_HAVE_HDF5) 2287 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2288 #else 2289 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2290 #endif 2291 } 2292 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2293 PetscFunctionReturn(PETSC_SUCCESS); 2294 } 2295 2296 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2297 { 2298 PetscBool ishdf5; 2299 2300 PetscFunctionBegin; 2301 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2302 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2303 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2304 if (ishdf5) { 2305 #if defined(PETSC_HAVE_HDF5) 2306 PetscViewerFormat format; 2307 PetscCall(PetscViewerGetFormat(viewer, &format)); 2308 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2309 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2310 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2311 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2312 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2313 PetscFunctionReturn(PETSC_SUCCESS); 2314 #else 2315 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2316 #endif 2317 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2318 } 2319 2320 /*@ 2321 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2322 2323 Collective 2324 2325 Input Parameters: 2326 + dm - The `DM` into which the topology is loaded 2327 - viewer - The `PetscViewer` for the saved topology 2328 2329 Output Parameter: 2330 . 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 2331 2332 Level: advanced 2333 2334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2335 `PetscViewer`, `PetscSF` 2336 @*/ 2337 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2338 { 2339 PetscBool ishdf5; 2340 2341 PetscFunctionBegin; 2342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2343 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2344 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2345 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2346 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2347 if (ishdf5) { 2348 #if defined(PETSC_HAVE_HDF5) 2349 PetscViewerFormat format; 2350 PetscCall(PetscViewerGetFormat(viewer, &format)); 2351 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2352 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2353 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2354 #else 2355 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2356 #endif 2357 } 2358 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2359 PetscFunctionReturn(PETSC_SUCCESS); 2360 } 2361 2362 /*@ 2363 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2364 2365 Collective 2366 2367 Input Parameters: 2368 + dm - The `DM` into which the coordinates are loaded 2369 . viewer - The `PetscViewer` for the saved coordinates 2370 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2371 2372 Level: advanced 2373 2374 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2375 `PetscSF`, `PetscViewer` 2376 @*/ 2377 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2378 { 2379 PetscBool ishdf5; 2380 2381 PetscFunctionBegin; 2382 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2383 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2384 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2385 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2386 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2387 if (ishdf5) { 2388 #if defined(PETSC_HAVE_HDF5) 2389 PetscViewerFormat format; 2390 PetscCall(PetscViewerGetFormat(viewer, &format)); 2391 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2392 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2393 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2394 #else 2395 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2396 #endif 2397 } 2398 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2399 PetscFunctionReturn(PETSC_SUCCESS); 2400 } 2401 2402 /*@ 2403 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2404 2405 Collective 2406 2407 Input Parameters: 2408 + dm - The `DM` into which the labels are loaded 2409 . viewer - The `PetscViewer` for the saved labels 2410 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2411 2412 Level: advanced 2413 2414 Note: 2415 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2416 2417 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2418 `PetscSF`, `PetscViewer` 2419 @*/ 2420 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2421 { 2422 PetscBool ishdf5; 2423 2424 PetscFunctionBegin; 2425 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2426 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2427 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2428 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2429 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2430 if (ishdf5) { 2431 #if defined(PETSC_HAVE_HDF5) 2432 PetscViewerFormat format; 2433 2434 PetscCall(PetscViewerGetFormat(viewer, &format)); 2435 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2436 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2437 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2438 #else 2439 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2440 #endif 2441 } 2442 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2443 PetscFunctionReturn(PETSC_SUCCESS); 2444 } 2445 2446 /*@ 2447 DMPlexSectionLoad - Loads section into a `DMPLEX` 2448 2449 Collective 2450 2451 Input Parameters: 2452 + dm - The `DM` that represents the topology 2453 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2454 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2455 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2456 2457 Output Parameters: 2458 + 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) 2459 - 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) 2460 2461 Level: advanced 2462 2463 Notes: 2464 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. 2465 2466 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 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. 2467 2468 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. 2469 2470 Example using 2 processes: 2471 .vb 2472 NX (number of points on dm): 4 2473 sectionA : the on-disk section 2474 vecA : a vector associated with sectionA 2475 sectionB : sectiondm's local section constructed in this function 2476 vecB (local) : a vector associated with sectiondm's local section 2477 vecB (global) : a vector associated with sectiondm's global section 2478 2479 rank 0 rank 1 2480 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2481 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2482 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2483 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2484 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2485 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2486 sectionB->atlasDof : 1 0 1 | 1 3 2487 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2488 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2489 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2490 .ve 2491 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2492 2493 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2494 @*/ 2495 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2496 { 2497 PetscBool ishdf5; 2498 2499 PetscFunctionBegin; 2500 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2501 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2502 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2503 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2504 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2505 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2506 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2507 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2508 if (ishdf5) { 2509 #if defined(PETSC_HAVE_HDF5) 2510 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2511 #else 2512 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2513 #endif 2514 } 2515 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2516 PetscFunctionReturn(PETSC_SUCCESS); 2517 } 2518 2519 /*@ 2520 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2521 2522 Collective 2523 2524 Input Parameters: 2525 + dm - The `DM` that represents the topology 2526 . viewer - The `PetscViewer` that represents the on-disk vector data 2527 . sectiondm - The `DM` that contains the global section on which vec is defined 2528 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2529 - vec - The global vector to set values of 2530 2531 Level: advanced 2532 2533 Notes: 2534 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 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. 2535 2536 Calling sequence: 2537 .vb 2538 DMCreate(PETSC_COMM_WORLD, &dm); 2539 DMSetType(dm, DMPLEX); 2540 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2541 DMPlexTopologyLoad(dm, viewer, &sfX); 2542 DMClone(dm, §iondm); 2543 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2544 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2545 DMGetGlobalVector(sectiondm, &vec); 2546 PetscObjectSetName((PetscObject)vec, "vec_name"); 2547 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2548 DMRestoreGlobalVector(sectiondm, &vec); 2549 PetscSFDestroy(&gsf); 2550 PetscSFDestroy(&sfX); 2551 DMDestroy(§iondm); 2552 DMDestroy(&dm); 2553 .ve 2554 2555 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2556 `PetscSF`, `PetscViewer` 2557 @*/ 2558 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2559 { 2560 PetscBool ishdf5; 2561 2562 PetscFunctionBegin; 2563 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2564 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2565 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2566 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2567 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2568 /* Check consistency */ 2569 { 2570 PetscSection section; 2571 PetscBool includesConstraints; 2572 PetscInt m, m1; 2573 2574 PetscCall(VecGetLocalSize(vec, &m1)); 2575 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2576 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2577 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2578 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2579 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2580 } 2581 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2582 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2583 if (ishdf5) { 2584 #if defined(PETSC_HAVE_HDF5) 2585 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2586 #else 2587 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2588 #endif 2589 } 2590 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2591 PetscFunctionReturn(PETSC_SUCCESS); 2592 } 2593 2594 /*@ 2595 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2596 2597 Collective 2598 2599 Input Parameters: 2600 + dm - The `DM` that represents the topology 2601 . viewer - The `PetscViewer` that represents the on-disk vector data 2602 . sectiondm - The `DM` that contains the local section on which vec is defined 2603 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2604 - vec - The local vector to set values of 2605 2606 Level: advanced 2607 2608 Notes: 2609 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 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. 2610 2611 Calling sequence: 2612 .vb 2613 DMCreate(PETSC_COMM_WORLD, &dm); 2614 DMSetType(dm, DMPLEX); 2615 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2616 DMPlexTopologyLoad(dm, viewer, &sfX); 2617 DMClone(dm, §iondm); 2618 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2619 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2620 DMGetLocalVector(sectiondm, &vec); 2621 PetscObjectSetName((PetscObject)vec, "vec_name"); 2622 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2623 DMRestoreLocalVector(sectiondm, &vec); 2624 PetscSFDestroy(&lsf); 2625 PetscSFDestroy(&sfX); 2626 DMDestroy(§iondm); 2627 DMDestroy(&dm); 2628 .ve 2629 2630 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2631 `PetscSF`, `PetscViewer` 2632 @*/ 2633 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2634 { 2635 PetscBool ishdf5; 2636 2637 PetscFunctionBegin; 2638 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2639 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2640 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2641 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2642 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2643 /* Check consistency */ 2644 { 2645 PetscSection section; 2646 PetscBool includesConstraints; 2647 PetscInt m, m1; 2648 2649 PetscCall(VecGetLocalSize(vec, &m1)); 2650 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2651 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2652 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2653 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2654 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2655 } 2656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2657 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2658 if (ishdf5) { 2659 #if defined(PETSC_HAVE_HDF5) 2660 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2661 #else 2662 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2663 #endif 2664 } 2665 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2666 PetscFunctionReturn(PETSC_SUCCESS); 2667 } 2668 2669 PetscErrorCode DMDestroy_Plex(DM dm) 2670 { 2671 DM_Plex *mesh = (DM_Plex *)dm->data; 2672 2673 PetscFunctionBegin; 2674 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2675 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2676 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2677 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2678 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2679 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2680 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2681 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2682 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2683 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2684 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2685 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2686 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2687 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2688 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2689 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2690 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2691 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2692 PetscCall(PetscFree(mesh->cones)); 2693 PetscCall(PetscFree(mesh->coneOrientations)); 2694 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2695 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2696 PetscCall(PetscFree(mesh->supports)); 2697 PetscCall(PetscFree(mesh->cellTypes)); 2698 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2699 PetscCall(PetscFree(mesh->tetgenOpts)); 2700 PetscCall(PetscFree(mesh->triangleOpts)); 2701 PetscCall(PetscFree(mesh->transformType)); 2702 PetscCall(PetscFree(mesh->distributionName)); 2703 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2704 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2705 PetscCall(ISDestroy(&mesh->subpointIS)); 2706 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2707 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2708 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2709 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2710 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2711 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2712 PetscCall(ISDestroy(&mesh->anchorIS)); 2713 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2714 PetscCall(PetscFree(mesh->parents)); 2715 PetscCall(PetscFree(mesh->childIDs)); 2716 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2717 PetscCall(PetscFree(mesh->children)); 2718 PetscCall(DMDestroy(&mesh->referenceTree)); 2719 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2720 PetscCall(PetscFree(mesh->neighbors)); 2721 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2722 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2723 PetscCall(PetscFree(mesh)); 2724 PetscFunctionReturn(PETSC_SUCCESS); 2725 } 2726 2727 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2728 { 2729 PetscSection sectionGlobal; 2730 PetscInt bs = -1, mbs; 2731 PetscInt localSize, localStart = 0; 2732 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2733 MatType mtype; 2734 ISLocalToGlobalMapping ltog; 2735 2736 PetscFunctionBegin; 2737 PetscCall(MatInitializePackage()); 2738 mtype = dm->mattype; 2739 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2740 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2741 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2742 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2743 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2744 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2745 PetscCall(MatSetType(*J, mtype)); 2746 PetscCall(MatSetFromOptions(*J)); 2747 PetscCall(MatGetBlockSize(*J, &mbs)); 2748 if (mbs > 1) bs = mbs; 2749 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2750 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2751 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2752 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2753 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2754 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2755 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2756 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2757 if (!isShell) { 2758 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2759 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2760 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2761 2762 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2763 2764 PetscCall(PetscCalloc1(localSize, &pblocks)); 2765 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2766 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2767 for (p = pStart; p < pEnd; ++p) { 2768 switch (dm->blocking_type) { 2769 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2770 PetscInt bdof, offset; 2771 2772 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2773 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2774 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2775 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2776 dof = dof < 0 ? -(dof + 1) : dof; 2777 bdof = cdof && (dof - cdof) ? 1 : dof; 2778 if (dof) { 2779 if (bs < 0) { 2780 bs = bdof; 2781 } else if (bs != bdof) { 2782 bs = 1; 2783 } 2784 } 2785 } break; 2786 case DM_BLOCKING_FIELD_NODE: { 2787 for (PetscInt field = 0; field < num_fields; field++) { 2788 PetscInt num_comp, bdof, offset; 2789 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2790 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2791 if (dof < 0) continue; 2792 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2793 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2794 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); 2795 PetscInt num_nodes = dof / num_comp; 2796 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2797 // Handle possibly constant block size (unlikely) 2798 bdof = cdof && (dof - cdof) ? 1 : dof; 2799 if (dof) { 2800 if (bs < 0) { 2801 bs = bdof; 2802 } else if (bs != bdof) { 2803 bs = 1; 2804 } 2805 } 2806 } 2807 } break; 2808 } 2809 } 2810 /* Must have same blocksize on all procs (some might have no points) */ 2811 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2812 bsLocal[1] = bs; 2813 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2814 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2815 else bs = bsMinMax[0]; 2816 bs = PetscMax(1, bs); 2817 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2818 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2819 PetscCall(MatSetBlockSize(*J, bs)); 2820 PetscCall(MatSetUp(*J)); 2821 } else { 2822 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2823 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2824 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2825 } 2826 { // Consolidate blocks 2827 PetscInt nblocks = 0; 2828 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2829 if (pblocks[i] == 0) continue; 2830 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2831 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]); 2832 } 2833 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2834 } 2835 PetscCall(PetscFree(pblocks)); 2836 } 2837 PetscCall(MatSetDM(*J, dm)); 2838 PetscFunctionReturn(PETSC_SUCCESS); 2839 } 2840 2841 /*@ 2842 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2843 2844 Not Collective 2845 2846 Input Parameter: 2847 . dm - The `DMPLEX` 2848 2849 Output Parameter: 2850 . subsection - The subdomain section 2851 2852 Level: developer 2853 2854 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2855 @*/ 2856 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2857 { 2858 DM_Plex *mesh = (DM_Plex *)dm->data; 2859 2860 PetscFunctionBegin; 2861 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2862 if (!mesh->subdomainSection) { 2863 PetscSection section; 2864 PetscSF sf; 2865 2866 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2867 PetscCall(DMGetLocalSection(dm, §ion)); 2868 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2869 PetscCall(PetscSFDestroy(&sf)); 2870 } 2871 *subsection = mesh->subdomainSection; 2872 PetscFunctionReturn(PETSC_SUCCESS); 2873 } 2874 2875 /*@ 2876 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2877 2878 Not Collective 2879 2880 Input Parameter: 2881 . dm - The `DMPLEX` 2882 2883 Output Parameters: 2884 + pStart - The first mesh point 2885 - pEnd - The upper bound for mesh points 2886 2887 Level: beginner 2888 2889 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2890 @*/ 2891 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2892 { 2893 DM_Plex *mesh = (DM_Plex *)dm->data; 2894 2895 PetscFunctionBegin; 2896 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2897 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2898 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2899 PetscFunctionReturn(PETSC_SUCCESS); 2900 } 2901 2902 /*@ 2903 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2904 2905 Not Collective 2906 2907 Input Parameters: 2908 + dm - The `DMPLEX` 2909 . pStart - The first mesh point 2910 - pEnd - The upper bound for mesh points 2911 2912 Level: beginner 2913 2914 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2915 @*/ 2916 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2917 { 2918 DM_Plex *mesh = (DM_Plex *)dm->data; 2919 2920 PetscFunctionBegin; 2921 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2922 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2923 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2924 PetscCall(PetscFree(mesh->cellTypes)); 2925 PetscFunctionReturn(PETSC_SUCCESS); 2926 } 2927 2928 /*@ 2929 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2930 2931 Not Collective 2932 2933 Input Parameters: 2934 + dm - The `DMPLEX` 2935 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2936 2937 Output Parameter: 2938 . size - The cone size for point `p` 2939 2940 Level: beginner 2941 2942 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2943 @*/ 2944 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2945 { 2946 DM_Plex *mesh = (DM_Plex *)dm->data; 2947 2948 PetscFunctionBegin; 2949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2950 PetscAssertPointer(size, 3); 2951 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2952 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2953 PetscFunctionReturn(PETSC_SUCCESS); 2954 } 2955 2956 /*@ 2957 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2958 2959 Not Collective 2960 2961 Input Parameters: 2962 + dm - The `DMPLEX` 2963 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2964 - size - The cone size for point `p` 2965 2966 Level: beginner 2967 2968 Note: 2969 This should be called after `DMPlexSetChart()`. 2970 2971 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2972 @*/ 2973 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2974 { 2975 DM_Plex *mesh = (DM_Plex *)dm->data; 2976 2977 PetscFunctionBegin; 2978 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2979 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2980 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2981 PetscFunctionReturn(PETSC_SUCCESS); 2982 } 2983 2984 /*@C 2985 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2986 2987 Not Collective 2988 2989 Input Parameters: 2990 + dm - The `DMPLEX` 2991 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2992 2993 Output Parameter: 2994 . cone - An array of points which are on the in-edges for point `p` 2995 2996 Level: beginner 2997 2998 Fortran Notes: 2999 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3000 `DMPlexRestoreCone()` is not needed/available in C. 3001 3002 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3003 @*/ 3004 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3005 { 3006 DM_Plex *mesh = (DM_Plex *)dm->data; 3007 PetscInt off; 3008 3009 PetscFunctionBegin; 3010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3011 PetscAssertPointer(cone, 3); 3012 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3013 *cone = &mesh->cones[off]; 3014 PetscFunctionReturn(PETSC_SUCCESS); 3015 } 3016 3017 /*@C 3018 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3019 3020 Not Collective 3021 3022 Input Parameters: 3023 + dm - The `DMPLEX` 3024 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3025 3026 Output Parameters: 3027 + pConesSection - `PetscSection` describing the layout of `pCones` 3028 - pCones - An array of points which are on the in-edges for the point set `p` 3029 3030 Level: intermediate 3031 3032 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3033 @*/ 3034 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3035 { 3036 PetscSection cs, newcs; 3037 PetscInt *cones; 3038 PetscInt *newarr = NULL; 3039 PetscInt n; 3040 3041 PetscFunctionBegin; 3042 PetscCall(DMPlexGetCones(dm, &cones)); 3043 PetscCall(DMPlexGetConeSection(dm, &cs)); 3044 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3045 if (pConesSection) *pConesSection = newcs; 3046 if (pCones) { 3047 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3048 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3049 } 3050 PetscFunctionReturn(PETSC_SUCCESS); 3051 } 3052 3053 /*@ 3054 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3055 3056 Not Collective 3057 3058 Input Parameters: 3059 + dm - The `DMPLEX` 3060 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3061 3062 Output Parameter: 3063 . expandedPoints - An array of vertices recursively expanded from input points 3064 3065 Level: advanced 3066 3067 Notes: 3068 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3069 3070 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3071 3072 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3073 `DMPlexGetDepth()`, `IS` 3074 @*/ 3075 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3076 { 3077 IS *expandedPointsAll; 3078 PetscInt depth; 3079 3080 PetscFunctionBegin; 3081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3082 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3083 PetscAssertPointer(expandedPoints, 3); 3084 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3085 *expandedPoints = expandedPointsAll[0]; 3086 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3087 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3088 PetscFunctionReturn(PETSC_SUCCESS); 3089 } 3090 3091 /*@ 3092 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). 3093 3094 Not Collective 3095 3096 Input Parameters: 3097 + dm - The `DMPLEX` 3098 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3099 3100 Output Parameters: 3101 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3102 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3103 - sections - (optional) An array of sections which describe mappings from points to their cone points 3104 3105 Level: advanced 3106 3107 Notes: 3108 Like `DMPlexGetConeTuple()` but recursive. 3109 3110 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. 3111 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3112 3113 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\: 3114 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3115 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3116 3117 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3118 `DMPlexGetDepth()`, `PetscSection`, `IS` 3119 @*/ 3120 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3121 { 3122 const PetscInt *arr0 = NULL, *cone = NULL; 3123 PetscInt *arr = NULL, *newarr = NULL; 3124 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3125 IS *expandedPoints_; 3126 PetscSection *sections_; 3127 3128 PetscFunctionBegin; 3129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3130 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3131 if (depth) PetscAssertPointer(depth, 3); 3132 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3133 if (sections) PetscAssertPointer(sections, 5); 3134 PetscCall(ISGetLocalSize(points, &n)); 3135 PetscCall(ISGetIndices(points, &arr0)); 3136 PetscCall(DMPlexGetDepth(dm, &depth_)); 3137 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3138 PetscCall(PetscCalloc1(depth_, §ions_)); 3139 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3140 for (d = depth_ - 1; d >= 0; d--) { 3141 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3142 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3143 for (i = 0; i < n; i++) { 3144 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3145 if (arr[i] >= start && arr[i] < end) { 3146 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3147 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3148 } else { 3149 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3150 } 3151 } 3152 PetscCall(PetscSectionSetUp(sections_[d])); 3153 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3154 PetscCall(PetscMalloc1(newn, &newarr)); 3155 for (i = 0; i < n; i++) { 3156 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3157 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3158 if (cn > 1) { 3159 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3160 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3161 } else { 3162 newarr[co] = arr[i]; 3163 } 3164 } 3165 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3166 arr = newarr; 3167 n = newn; 3168 } 3169 PetscCall(ISRestoreIndices(points, &arr0)); 3170 *depth = depth_; 3171 if (expandedPoints) *expandedPoints = expandedPoints_; 3172 else { 3173 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3174 PetscCall(PetscFree(expandedPoints_)); 3175 } 3176 if (sections) *sections = sections_; 3177 else { 3178 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3179 PetscCall(PetscFree(sections_)); 3180 } 3181 PetscFunctionReturn(PETSC_SUCCESS); 3182 } 3183 3184 /*@ 3185 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3186 3187 Not Collective 3188 3189 Input Parameters: 3190 + dm - The `DMPLEX` 3191 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3192 3193 Output Parameters: 3194 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3195 . expandedPoints - (optional) An array of recursively expanded cones 3196 - sections - (optional) An array of sections which describe mappings from points to their cone points 3197 3198 Level: advanced 3199 3200 Note: 3201 See `DMPlexGetConeRecursive()` 3202 3203 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3204 `DMPlexGetDepth()`, `IS`, `PetscSection` 3205 @*/ 3206 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3207 { 3208 PetscInt d, depth_; 3209 3210 PetscFunctionBegin; 3211 PetscCall(DMPlexGetDepth(dm, &depth_)); 3212 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3213 if (depth) *depth = 0; 3214 if (expandedPoints) { 3215 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3216 PetscCall(PetscFree(*expandedPoints)); 3217 } 3218 if (sections) { 3219 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3220 PetscCall(PetscFree(*sections)); 3221 } 3222 PetscFunctionReturn(PETSC_SUCCESS); 3223 } 3224 3225 /*@ 3226 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 3227 3228 Not Collective 3229 3230 Input Parameters: 3231 + dm - The `DMPLEX` 3232 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3233 - cone - An array of points which are on the in-edges for point `p` 3234 3235 Level: beginner 3236 3237 Note: 3238 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3239 3240 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3241 @*/ 3242 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3243 { 3244 DM_Plex *mesh = (DM_Plex *)dm->data; 3245 PetscInt dof, off, c; 3246 3247 PetscFunctionBegin; 3248 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3249 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3250 if (dof) PetscAssertPointer(cone, 3); 3251 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3252 if (PetscDefined(USE_DEBUG)) { 3253 PetscInt pStart, pEnd; 3254 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3255 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); 3256 for (c = 0; c < dof; ++c) { 3257 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); 3258 mesh->cones[off + c] = cone[c]; 3259 } 3260 } else { 3261 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3262 } 3263 PetscFunctionReturn(PETSC_SUCCESS); 3264 } 3265 3266 /*@C 3267 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3268 3269 Not Collective 3270 3271 Input Parameters: 3272 + dm - The `DMPLEX` 3273 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3274 3275 Output Parameter: 3276 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3277 integer giving the prescription for cone traversal. 3278 3279 Level: beginner 3280 3281 Note: 3282 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3283 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3284 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3285 with the identity. 3286 3287 Fortran Notes: 3288 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3289 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3290 3291 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3292 @*/ 3293 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3294 { 3295 DM_Plex *mesh = (DM_Plex *)dm->data; 3296 PetscInt off; 3297 3298 PetscFunctionBegin; 3299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3300 if (PetscDefined(USE_DEBUG)) { 3301 PetscInt dof; 3302 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3303 if (dof) PetscAssertPointer(coneOrientation, 3); 3304 } 3305 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3306 3307 *coneOrientation = &mesh->coneOrientations[off]; 3308 PetscFunctionReturn(PETSC_SUCCESS); 3309 } 3310 3311 /*@ 3312 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3313 3314 Not Collective 3315 3316 Input Parameters: 3317 + dm - The `DMPLEX` 3318 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3319 - coneOrientation - An array of orientations 3320 3321 Level: beginner 3322 3323 Notes: 3324 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3325 3326 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3327 3328 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3329 @*/ 3330 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3331 { 3332 DM_Plex *mesh = (DM_Plex *)dm->data; 3333 PetscInt pStart, pEnd; 3334 PetscInt dof, off, c; 3335 3336 PetscFunctionBegin; 3337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3338 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3339 if (dof) PetscAssertPointer(coneOrientation, 3); 3340 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3341 if (PetscDefined(USE_DEBUG)) { 3342 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3343 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); 3344 for (c = 0; c < dof; ++c) { 3345 PetscInt cdof, o = coneOrientation[c]; 3346 3347 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3348 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); 3349 mesh->coneOrientations[off + c] = o; 3350 } 3351 } else { 3352 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3353 } 3354 PetscFunctionReturn(PETSC_SUCCESS); 3355 } 3356 3357 /*@ 3358 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3359 3360 Not Collective 3361 3362 Input Parameters: 3363 + dm - The `DMPLEX` 3364 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3365 . conePos - The local index in the cone where the point should be put 3366 - conePoint - The mesh point to insert 3367 3368 Level: beginner 3369 3370 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3371 @*/ 3372 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3373 { 3374 DM_Plex *mesh = (DM_Plex *)dm->data; 3375 PetscInt pStart, pEnd; 3376 PetscInt dof, off; 3377 3378 PetscFunctionBegin; 3379 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3380 if (PetscDefined(USE_DEBUG)) { 3381 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3382 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3383 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); 3384 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3385 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); 3386 } 3387 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3388 mesh->cones[off + conePos] = conePoint; 3389 PetscFunctionReturn(PETSC_SUCCESS); 3390 } 3391 3392 /*@ 3393 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3394 3395 Not Collective 3396 3397 Input Parameters: 3398 + dm - The `DMPLEX` 3399 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3400 . conePos - The local index in the cone where the point should be put 3401 - coneOrientation - The point orientation to insert 3402 3403 Level: beginner 3404 3405 Note: 3406 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3407 3408 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3409 @*/ 3410 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3411 { 3412 DM_Plex *mesh = (DM_Plex *)dm->data; 3413 PetscInt pStart, pEnd; 3414 PetscInt dof, off; 3415 3416 PetscFunctionBegin; 3417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3418 if (PetscDefined(USE_DEBUG)) { 3419 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3420 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); 3421 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3422 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); 3423 } 3424 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3425 mesh->coneOrientations[off + conePos] = coneOrientation; 3426 PetscFunctionReturn(PETSC_SUCCESS); 3427 } 3428 3429 /*@C 3430 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3431 3432 Not collective 3433 3434 Input Parameters: 3435 + dm - The DMPlex 3436 - p - The point, which must lie in the chart set with DMPlexSetChart() 3437 3438 Output Parameters: 3439 + cone - An array of points which are on the in-edges for point `p` 3440 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3441 integer giving the prescription for cone traversal. 3442 3443 Level: beginner 3444 3445 Notes: 3446 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3447 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3448 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3449 with the identity. 3450 3451 Fortran Notes: 3452 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3453 `DMPlexRestoreCone()` is not needed/available in C. 3454 3455 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3456 @*/ 3457 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3458 { 3459 DM_Plex *mesh = (DM_Plex *)dm->data; 3460 3461 PetscFunctionBegin; 3462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3463 if (mesh->tr) { 3464 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3465 } else { 3466 PetscInt off; 3467 if (PetscDefined(USE_DEBUG)) { 3468 PetscInt dof; 3469 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3470 if (dof) { 3471 if (cone) PetscAssertPointer(cone, 3); 3472 if (ornt) PetscAssertPointer(ornt, 4); 3473 } 3474 } 3475 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3476 if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB 3477 if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL; 3478 } 3479 PetscFunctionReturn(PETSC_SUCCESS); 3480 } 3481 3482 /*@C 3483 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3484 3485 Not Collective 3486 3487 Input Parameters: 3488 + dm - The DMPlex 3489 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3490 . cone - An array of points which are on the in-edges for point p 3491 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3492 integer giving the prescription for cone traversal. 3493 3494 Level: beginner 3495 3496 Notes: 3497 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3498 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3499 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3500 with the identity. 3501 3502 Fortran Notes: 3503 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3504 `DMPlexRestoreCone()` is not needed/available in C. 3505 3506 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3507 @*/ 3508 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3509 { 3510 DM_Plex *mesh = (DM_Plex *)dm->data; 3511 3512 PetscFunctionBegin; 3513 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3514 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3515 PetscFunctionReturn(PETSC_SUCCESS); 3516 } 3517 3518 /*@ 3519 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3520 3521 Not Collective 3522 3523 Input Parameters: 3524 + dm - The `DMPLEX` 3525 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3526 3527 Output Parameter: 3528 . size - The support size for point `p` 3529 3530 Level: beginner 3531 3532 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3533 @*/ 3534 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3535 { 3536 DM_Plex *mesh = (DM_Plex *)dm->data; 3537 3538 PetscFunctionBegin; 3539 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3540 PetscAssertPointer(size, 3); 3541 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3542 PetscFunctionReturn(PETSC_SUCCESS); 3543 } 3544 3545 /*@ 3546 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3547 3548 Not Collective 3549 3550 Input Parameters: 3551 + dm - The `DMPLEX` 3552 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3553 - size - The support size for point `p` 3554 3555 Level: beginner 3556 3557 Note: 3558 This should be called after `DMPlexSetChart()`. 3559 3560 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3561 @*/ 3562 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3563 { 3564 DM_Plex *mesh = (DM_Plex *)dm->data; 3565 3566 PetscFunctionBegin; 3567 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3568 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3569 PetscFunctionReturn(PETSC_SUCCESS); 3570 } 3571 3572 /*@C 3573 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3574 3575 Not Collective 3576 3577 Input Parameters: 3578 + dm - The `DMPLEX` 3579 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3580 3581 Output Parameter: 3582 . support - An array of points which are on the out-edges for point `p` 3583 3584 Level: beginner 3585 3586 Fortran Notes: 3587 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3588 `DMPlexRestoreSupport()` is not needed/available in C. 3589 3590 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3591 @*/ 3592 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3593 { 3594 DM_Plex *mesh = (DM_Plex *)dm->data; 3595 PetscInt off; 3596 3597 PetscFunctionBegin; 3598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3599 PetscAssertPointer(support, 3); 3600 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3601 *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB 3602 PetscFunctionReturn(PETSC_SUCCESS); 3603 } 3604 3605 /*@ 3606 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3607 3608 Not Collective 3609 3610 Input Parameters: 3611 + dm - The `DMPLEX` 3612 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3613 - support - An array of points which are on the out-edges for point `p` 3614 3615 Level: beginner 3616 3617 Note: 3618 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3619 3620 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3621 @*/ 3622 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3623 { 3624 DM_Plex *mesh = (DM_Plex *)dm->data; 3625 PetscInt pStart, pEnd; 3626 PetscInt dof, off, c; 3627 3628 PetscFunctionBegin; 3629 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3630 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3631 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3632 if (dof) PetscAssertPointer(support, 3); 3633 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3634 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); 3635 for (c = 0; c < dof; ++c) { 3636 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); 3637 mesh->supports[off + c] = support[c]; 3638 } 3639 PetscFunctionReturn(PETSC_SUCCESS); 3640 } 3641 3642 /*@ 3643 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3644 3645 Not Collective 3646 3647 Input Parameters: 3648 + dm - The `DMPLEX` 3649 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3650 . supportPos - The local index in the cone where the point should be put 3651 - supportPoint - The mesh point to insert 3652 3653 Level: beginner 3654 3655 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3656 @*/ 3657 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3658 { 3659 DM_Plex *mesh = (DM_Plex *)dm->data; 3660 PetscInt pStart, pEnd; 3661 PetscInt dof, off; 3662 3663 PetscFunctionBegin; 3664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3665 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3666 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3667 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3668 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); 3669 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); 3670 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); 3671 mesh->supports[off + supportPos] = supportPoint; 3672 PetscFunctionReturn(PETSC_SUCCESS); 3673 } 3674 3675 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3676 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3677 { 3678 switch (ct) { 3679 case DM_POLYTOPE_SEGMENT: 3680 if (o == -1) return -2; 3681 break; 3682 case DM_POLYTOPE_TRIANGLE: 3683 if (o == -3) return -1; 3684 if (o == -2) return -3; 3685 if (o == -1) return -2; 3686 break; 3687 case DM_POLYTOPE_QUADRILATERAL: 3688 if (o == -4) return -2; 3689 if (o == -3) return -1; 3690 if (o == -2) return -4; 3691 if (o == -1) return -3; 3692 break; 3693 default: 3694 return o; 3695 } 3696 return o; 3697 } 3698 3699 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3700 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3701 { 3702 switch (ct) { 3703 case DM_POLYTOPE_SEGMENT: 3704 if ((o == -2) || (o == 1)) return -1; 3705 if (o == -1) return 0; 3706 break; 3707 case DM_POLYTOPE_TRIANGLE: 3708 if (o == -3) return -2; 3709 if (o == -2) return -1; 3710 if (o == -1) return -3; 3711 break; 3712 case DM_POLYTOPE_QUADRILATERAL: 3713 if (o == -4) return -2; 3714 if (o == -3) return -1; 3715 if (o == -2) return -4; 3716 if (o == -1) return -3; 3717 break; 3718 default: 3719 return o; 3720 } 3721 return o; 3722 } 3723 3724 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3725 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3726 { 3727 PetscInt pStart, pEnd, p; 3728 3729 PetscFunctionBegin; 3730 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3731 for (p = pStart; p < pEnd; ++p) { 3732 const PetscInt *cone, *ornt; 3733 PetscInt coneSize, c; 3734 3735 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3736 PetscCall(DMPlexGetCone(dm, p, &cone)); 3737 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3738 for (c = 0; c < coneSize; ++c) { 3739 DMPolytopeType ct; 3740 const PetscInt o = ornt[c]; 3741 3742 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3743 switch (ct) { 3744 case DM_POLYTOPE_SEGMENT: 3745 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3746 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3747 break; 3748 case DM_POLYTOPE_TRIANGLE: 3749 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3750 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3751 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3752 break; 3753 case DM_POLYTOPE_QUADRILATERAL: 3754 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3755 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3756 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3757 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3758 break; 3759 default: 3760 break; 3761 } 3762 } 3763 } 3764 PetscFunctionReturn(PETSC_SUCCESS); 3765 } 3766 3767 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3768 { 3769 DM_Plex *mesh = (DM_Plex *)dm->data; 3770 3771 PetscFunctionBeginHot; 3772 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3773 if (useCone) { 3774 PetscCall(DMPlexGetConeSize(dm, p, size)); 3775 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3776 } else { 3777 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3778 PetscCall(DMPlexGetSupport(dm, p, arr)); 3779 } 3780 } else { 3781 if (useCone) { 3782 const PetscSection s = mesh->coneSection; 3783 const PetscInt ps = p - s->pStart; 3784 const PetscInt off = s->atlasOff[ps]; 3785 3786 *size = s->atlasDof[ps]; 3787 *arr = mesh->cones + off; 3788 *ornt = mesh->coneOrientations + off; 3789 } else { 3790 const PetscSection s = mesh->supportSection; 3791 const PetscInt ps = p - s->pStart; 3792 const PetscInt off = s->atlasOff[ps]; 3793 3794 *size = s->atlasDof[ps]; 3795 *arr = mesh->supports + off; 3796 } 3797 } 3798 PetscFunctionReturn(PETSC_SUCCESS); 3799 } 3800 3801 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3802 { 3803 DM_Plex *mesh = (DM_Plex *)dm->data; 3804 3805 PetscFunctionBeginHot; 3806 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3807 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3808 } 3809 PetscFunctionReturn(PETSC_SUCCESS); 3810 } 3811 3812 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3813 { 3814 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3815 PetscInt *closure; 3816 const PetscInt *tmp = NULL, *tmpO = NULL; 3817 PetscInt off = 0, tmpSize, t; 3818 3819 PetscFunctionBeginHot; 3820 if (ornt) { 3821 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3822 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; 3823 } 3824 if (*points) { 3825 closure = *points; 3826 } else { 3827 PetscInt maxConeSize, maxSupportSize; 3828 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3829 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3830 } 3831 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3832 if (ct == DM_POLYTOPE_UNKNOWN) { 3833 closure[off++] = p; 3834 closure[off++] = 0; 3835 for (t = 0; t < tmpSize; ++t) { 3836 closure[off++] = tmp[t]; 3837 closure[off++] = tmpO ? tmpO[t] : 0; 3838 } 3839 } else { 3840 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3841 3842 /* We assume that cells with a valid type have faces with a valid type */ 3843 closure[off++] = p; 3844 closure[off++] = ornt; 3845 for (t = 0; t < tmpSize; ++t) { 3846 DMPolytopeType ft; 3847 3848 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3849 closure[off++] = tmp[arr[t]]; 3850 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3851 } 3852 } 3853 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3854 if (numPoints) *numPoints = tmpSize + 1; 3855 if (points) *points = closure; 3856 PetscFunctionReturn(PETSC_SUCCESS); 3857 } 3858 3859 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3860 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3861 { 3862 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3863 const PetscInt *cone, *ornt; 3864 PetscInt *pts, *closure = NULL; 3865 DMPolytopeType ft; 3866 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3867 PetscInt dim, coneSize, c, d, clSize, cl; 3868 3869 PetscFunctionBeginHot; 3870 PetscCall(DMGetDimension(dm, &dim)); 3871 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3872 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3873 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3874 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3875 maxSize = PetscMax(coneSeries, supportSeries); 3876 if (*points) { 3877 pts = *points; 3878 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3879 c = 0; 3880 pts[c++] = point; 3881 pts[c++] = o; 3882 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3883 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3884 for (cl = 0; cl < clSize * 2; cl += 2) { 3885 pts[c++] = closure[cl]; 3886 pts[c++] = closure[cl + 1]; 3887 } 3888 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3889 for (cl = 0; cl < clSize * 2; cl += 2) { 3890 pts[c++] = closure[cl]; 3891 pts[c++] = closure[cl + 1]; 3892 } 3893 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3894 for (d = 2; d < coneSize; ++d) { 3895 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3896 pts[c++] = cone[arr[d * 2 + 0]]; 3897 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3898 } 3899 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3900 if (dim >= 3) { 3901 for (d = 2; d < coneSize; ++d) { 3902 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3903 const PetscInt *fcone, *fornt; 3904 PetscInt fconeSize, fc, i; 3905 3906 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3907 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3908 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3909 for (fc = 0; fc < fconeSize; ++fc) { 3910 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3911 const PetscInt co = farr[fc * 2 + 1]; 3912 3913 for (i = 0; i < c; i += 2) 3914 if (pts[i] == cp) break; 3915 if (i == c) { 3916 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3917 pts[c++] = cp; 3918 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3919 } 3920 } 3921 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3922 } 3923 } 3924 *numPoints = c / 2; 3925 *points = pts; 3926 PetscFunctionReturn(PETSC_SUCCESS); 3927 } 3928 3929 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3930 { 3931 DMPolytopeType ct; 3932 PetscInt *closure, *fifo; 3933 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3934 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3935 PetscInt depth, maxSize; 3936 3937 PetscFunctionBeginHot; 3938 PetscCall(DMPlexGetDepth(dm, &depth)); 3939 if (depth == 1) { 3940 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3941 PetscFunctionReturn(PETSC_SUCCESS); 3942 } 3943 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3944 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; 3945 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3946 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3947 PetscFunctionReturn(PETSC_SUCCESS); 3948 } 3949 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3950 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3951 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3952 maxSize = PetscMax(coneSeries, supportSeries); 3953 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3954 if (*points) { 3955 closure = *points; 3956 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3957 closure[closureSize++] = p; 3958 closure[closureSize++] = ornt; 3959 fifo[fifoSize++] = p; 3960 fifo[fifoSize++] = ornt; 3961 fifo[fifoSize++] = ct; 3962 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3963 while (fifoSize - fifoStart) { 3964 const PetscInt q = fifo[fifoStart++]; 3965 const PetscInt o = fifo[fifoStart++]; 3966 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3967 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3968 const PetscInt *tmp, *tmpO = NULL; 3969 PetscInt tmpSize, t; 3970 3971 if (PetscDefined(USE_DEBUG)) { 3972 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3973 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); 3974 } 3975 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3976 for (t = 0; t < tmpSize; ++t) { 3977 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3978 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3979 const PetscInt cp = tmp[ip]; 3980 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3981 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3982 PetscInt c; 3983 3984 /* Check for duplicate */ 3985 for (c = 0; c < closureSize; c += 2) { 3986 if (closure[c] == cp) break; 3987 } 3988 if (c == closureSize) { 3989 closure[closureSize++] = cp; 3990 closure[closureSize++] = co; 3991 fifo[fifoSize++] = cp; 3992 fifo[fifoSize++] = co; 3993 fifo[fifoSize++] = ct; 3994 } 3995 } 3996 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3997 } 3998 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3999 if (numPoints) *numPoints = closureSize / 2; 4000 if (points) *points = closure; 4001 PetscFunctionReturn(PETSC_SUCCESS); 4002 } 4003 4004 /*@C 4005 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4006 4007 Not Collective 4008 4009 Input Parameters: 4010 + dm - The `DMPLEX` 4011 . p - The mesh point 4012 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4013 4014 Input/Output Parameter: 4015 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4016 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4017 4018 Output Parameter: 4019 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4020 4021 Level: beginner 4022 4023 Note: 4024 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4025 4026 Fortran Notes: 4027 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4028 4029 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4030 @*/ 4031 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4032 { 4033 PetscFunctionBeginHot; 4034 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4035 if (numPoints) PetscAssertPointer(numPoints, 4); 4036 if (points) PetscAssertPointer(points, 5); 4037 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4038 PetscFunctionReturn(PETSC_SUCCESS); 4039 } 4040 4041 /*@C 4042 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4043 4044 Not Collective 4045 4046 Input Parameters: 4047 + dm - The `DMPLEX` 4048 . p - The mesh point 4049 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4050 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4051 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4052 4053 Level: beginner 4054 4055 Note: 4056 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4057 4058 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4059 @*/ 4060 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4061 { 4062 PetscFunctionBeginHot; 4063 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4064 if (numPoints) *numPoints = 0; 4065 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4066 PetscFunctionReturn(PETSC_SUCCESS); 4067 } 4068 4069 /*@ 4070 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4071 4072 Not Collective 4073 4074 Input Parameter: 4075 . dm - The `DMPLEX` 4076 4077 Output Parameters: 4078 + maxConeSize - The maximum number of in-edges 4079 - maxSupportSize - The maximum number of out-edges 4080 4081 Level: beginner 4082 4083 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4084 @*/ 4085 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4086 { 4087 DM_Plex *mesh = (DM_Plex *)dm->data; 4088 4089 PetscFunctionBegin; 4090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4091 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4092 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4093 PetscFunctionReturn(PETSC_SUCCESS); 4094 } 4095 4096 PetscErrorCode DMSetUp_Plex(DM dm) 4097 { 4098 DM_Plex *mesh = (DM_Plex *)dm->data; 4099 PetscInt size, maxSupportSize; 4100 4101 PetscFunctionBegin; 4102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4103 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4104 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4105 PetscCall(PetscMalloc1(size, &mesh->cones)); 4106 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4107 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4108 if (maxSupportSize) { 4109 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4110 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4111 PetscCall(PetscMalloc1(size, &mesh->supports)); 4112 } 4113 PetscFunctionReturn(PETSC_SUCCESS); 4114 } 4115 4116 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4117 { 4118 PetscFunctionBegin; 4119 if (subdm) PetscCall(DMClone(dm, subdm)); 4120 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 4121 if (subdm) (*subdm)->useNatural = dm->useNatural; 4122 if (dm->useNatural && dm->sfMigration) { 4123 PetscSF sfNatural; 4124 4125 (*subdm)->sfMigration = dm->sfMigration; 4126 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4127 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4128 (*subdm)->sfNatural = sfNatural; 4129 } 4130 PetscFunctionReturn(PETSC_SUCCESS); 4131 } 4132 4133 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4134 { 4135 PetscInt i = 0; 4136 4137 PetscFunctionBegin; 4138 PetscCall(DMClone(dms[0], superdm)); 4139 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4140 (*superdm)->useNatural = PETSC_FALSE; 4141 for (i = 0; i < len; i++) { 4142 if (dms[i]->useNatural && dms[i]->sfMigration) { 4143 PetscSF sfNatural; 4144 4145 (*superdm)->sfMigration = dms[i]->sfMigration; 4146 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4147 (*superdm)->useNatural = PETSC_TRUE; 4148 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4149 (*superdm)->sfNatural = sfNatural; 4150 break; 4151 } 4152 } 4153 PetscFunctionReturn(PETSC_SUCCESS); 4154 } 4155 4156 /*@ 4157 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4158 4159 Not Collective 4160 4161 Input Parameter: 4162 . dm - The `DMPLEX` 4163 4164 Level: beginner 4165 4166 Note: 4167 This should be called after all calls to `DMPlexSetCone()` 4168 4169 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4170 @*/ 4171 PetscErrorCode DMPlexSymmetrize(DM dm) 4172 { 4173 DM_Plex *mesh = (DM_Plex *)dm->data; 4174 PetscInt *offsets; 4175 PetscInt supportSize; 4176 PetscInt pStart, pEnd, p; 4177 4178 PetscFunctionBegin; 4179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4180 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4181 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4182 /* Calculate support sizes */ 4183 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4184 for (p = pStart; p < pEnd; ++p) { 4185 PetscInt dof, off, c; 4186 4187 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4188 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4189 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4190 } 4191 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4192 /* Calculate supports */ 4193 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4194 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4195 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4196 for (p = pStart; p < pEnd; ++p) { 4197 PetscInt dof, off, c; 4198 4199 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4200 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4201 for (c = off; c < off + dof; ++c) { 4202 const PetscInt q = mesh->cones[c]; 4203 PetscInt offS; 4204 4205 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4206 4207 mesh->supports[offS + offsets[q]] = p; 4208 ++offsets[q]; 4209 } 4210 } 4211 PetscCall(PetscFree(offsets)); 4212 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4213 PetscFunctionReturn(PETSC_SUCCESS); 4214 } 4215 4216 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4217 { 4218 IS stratumIS; 4219 4220 PetscFunctionBegin; 4221 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4222 if (PetscDefined(USE_DEBUG)) { 4223 PetscInt qStart, qEnd, numLevels, level; 4224 PetscBool overlap = PETSC_FALSE; 4225 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4226 for (level = 0; level < numLevels; level++) { 4227 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4228 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4229 overlap = PETSC_TRUE; 4230 break; 4231 } 4232 } 4233 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); 4234 } 4235 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4236 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4237 PetscCall(ISDestroy(&stratumIS)); 4238 PetscFunctionReturn(PETSC_SUCCESS); 4239 } 4240 4241 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4242 { 4243 PetscInt *pMin, *pMax; 4244 PetscInt pStart, pEnd; 4245 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4246 4247 PetscFunctionBegin; 4248 { 4249 DMLabel label2; 4250 4251 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4252 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4253 } 4254 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4255 for (PetscInt p = pStart; p < pEnd; ++p) { 4256 DMPolytopeType ct; 4257 4258 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4259 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4260 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4261 } 4262 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4263 for (PetscInt d = dmin; d <= dmax; ++d) { 4264 pMin[d] = PETSC_MAX_INT; 4265 pMax[d] = PETSC_MIN_INT; 4266 } 4267 for (PetscInt p = pStart; p < pEnd; ++p) { 4268 DMPolytopeType ct; 4269 PetscInt d; 4270 4271 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4272 d = DMPolytopeTypeGetDim(ct); 4273 pMin[d] = PetscMin(p, pMin[d]); 4274 pMax[d] = PetscMax(p, pMax[d]); 4275 } 4276 for (PetscInt d = dmin; d <= dmax; ++d) { 4277 if (pMin[d] > pMax[d]) continue; 4278 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4279 } 4280 PetscCall(PetscFree2(pMin, pMax)); 4281 PetscFunctionReturn(PETSC_SUCCESS); 4282 } 4283 4284 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4285 { 4286 PetscInt pStart, pEnd; 4287 PetscInt numRoots = 0, numLeaves = 0; 4288 4289 PetscFunctionBegin; 4290 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4291 { 4292 /* Initialize roots and count leaves */ 4293 PetscInt sMin = PETSC_MAX_INT; 4294 PetscInt sMax = PETSC_MIN_INT; 4295 PetscInt coneSize, supportSize; 4296 4297 for (PetscInt p = pStart; p < pEnd; ++p) { 4298 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4299 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4300 if (!coneSize && supportSize) { 4301 sMin = PetscMin(p, sMin); 4302 sMax = PetscMax(p, sMax); 4303 ++numRoots; 4304 } else if (!supportSize && coneSize) { 4305 ++numLeaves; 4306 } else if (!supportSize && !coneSize) { 4307 /* Isolated points */ 4308 sMin = PetscMin(p, sMin); 4309 sMax = PetscMax(p, sMax); 4310 } 4311 } 4312 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4313 } 4314 4315 if (numRoots + numLeaves == (pEnd - pStart)) { 4316 PetscInt sMin = PETSC_MAX_INT; 4317 PetscInt sMax = PETSC_MIN_INT; 4318 PetscInt coneSize, supportSize; 4319 4320 for (PetscInt p = pStart; p < pEnd; ++p) { 4321 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4322 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4323 if (!supportSize && coneSize) { 4324 sMin = PetscMin(p, sMin); 4325 sMax = PetscMax(p, sMax); 4326 } 4327 } 4328 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4329 } else { 4330 PetscInt level = 0; 4331 PetscInt qStart, qEnd; 4332 4333 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4334 while (qEnd > qStart) { 4335 PetscInt sMin = PETSC_MAX_INT; 4336 PetscInt sMax = PETSC_MIN_INT; 4337 4338 for (PetscInt q = qStart; q < qEnd; ++q) { 4339 const PetscInt *support; 4340 PetscInt supportSize; 4341 4342 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4343 PetscCall(DMPlexGetSupport(dm, q, &support)); 4344 for (PetscInt s = 0; s < supportSize; ++s) { 4345 sMin = PetscMin(support[s], sMin); 4346 sMax = PetscMax(support[s], sMax); 4347 } 4348 } 4349 PetscCall(DMLabelGetNumValues(label, &level)); 4350 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4351 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4352 } 4353 } 4354 PetscFunctionReturn(PETSC_SUCCESS); 4355 } 4356 4357 /*@ 4358 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4359 4360 Collective 4361 4362 Input Parameter: 4363 . dm - The `DMPLEX` 4364 4365 Level: beginner 4366 4367 Notes: 4368 The strata group all points of the same grade, and this function calculates the strata. This 4369 grade can be seen as the height (or depth) of the point in the DAG. 4370 4371 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4372 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4373 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4374 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4375 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4376 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4377 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4378 4379 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4380 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4381 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 4382 to interpolate only that one (e0), so that 4383 .vb 4384 cone(c0) = {e0, v2} 4385 cone(e0) = {v0, v1} 4386 .ve 4387 If `DMPlexStratify()` is run on this mesh, it will give depths 4388 .vb 4389 depth 0 = {v0, v1, v2} 4390 depth 1 = {e0, c0} 4391 .ve 4392 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4393 4394 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4395 4396 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4397 @*/ 4398 PetscErrorCode DMPlexStratify(DM dm) 4399 { 4400 DM_Plex *mesh = (DM_Plex *)dm->data; 4401 DMLabel label; 4402 PetscBool flg = PETSC_FALSE; 4403 4404 PetscFunctionBegin; 4405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4406 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4407 4408 // Create depth label 4409 PetscCall(DMCreateLabel(dm, "depth")); 4410 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4411 4412 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4413 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4414 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4415 4416 { /* just in case there is an empty process */ 4417 PetscInt numValues, maxValues = 0, v; 4418 4419 PetscCall(DMLabelGetNumValues(label, &numValues)); 4420 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4421 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4422 } 4423 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4424 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4425 PetscFunctionReturn(PETSC_SUCCESS); 4426 } 4427 4428 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4429 { 4430 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4431 PetscInt dim, depth, pheight, coneSize; 4432 4433 PetscFunctionBeginHot; 4434 PetscCall(DMGetDimension(dm, &dim)); 4435 PetscCall(DMPlexGetDepth(dm, &depth)); 4436 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4437 pheight = depth - pdepth; 4438 if (depth <= 1) { 4439 switch (pdepth) { 4440 case 0: 4441 ct = DM_POLYTOPE_POINT; 4442 break; 4443 case 1: 4444 switch (coneSize) { 4445 case 2: 4446 ct = DM_POLYTOPE_SEGMENT; 4447 break; 4448 case 3: 4449 ct = DM_POLYTOPE_TRIANGLE; 4450 break; 4451 case 4: 4452 switch (dim) { 4453 case 2: 4454 ct = DM_POLYTOPE_QUADRILATERAL; 4455 break; 4456 case 3: 4457 ct = DM_POLYTOPE_TETRAHEDRON; 4458 break; 4459 default: 4460 break; 4461 } 4462 break; 4463 case 5: 4464 ct = DM_POLYTOPE_PYRAMID; 4465 break; 4466 case 6: 4467 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4468 break; 4469 case 8: 4470 ct = DM_POLYTOPE_HEXAHEDRON; 4471 break; 4472 default: 4473 break; 4474 } 4475 } 4476 } else { 4477 if (pdepth == 0) { 4478 ct = DM_POLYTOPE_POINT; 4479 } else if (pheight == 0) { 4480 switch (dim) { 4481 case 1: 4482 switch (coneSize) { 4483 case 2: 4484 ct = DM_POLYTOPE_SEGMENT; 4485 break; 4486 default: 4487 break; 4488 } 4489 break; 4490 case 2: 4491 switch (coneSize) { 4492 case 3: 4493 ct = DM_POLYTOPE_TRIANGLE; 4494 break; 4495 case 4: 4496 ct = DM_POLYTOPE_QUADRILATERAL; 4497 break; 4498 default: 4499 break; 4500 } 4501 break; 4502 case 3: 4503 switch (coneSize) { 4504 case 4: 4505 ct = DM_POLYTOPE_TETRAHEDRON; 4506 break; 4507 case 5: { 4508 const PetscInt *cone; 4509 PetscInt faceConeSize; 4510 4511 PetscCall(DMPlexGetCone(dm, p, &cone)); 4512 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4513 switch (faceConeSize) { 4514 case 3: 4515 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4516 break; 4517 case 4: 4518 ct = DM_POLYTOPE_PYRAMID; 4519 break; 4520 } 4521 } break; 4522 case 6: 4523 ct = DM_POLYTOPE_HEXAHEDRON; 4524 break; 4525 default: 4526 break; 4527 } 4528 break; 4529 default: 4530 break; 4531 } 4532 } else if (pheight > 0) { 4533 switch (coneSize) { 4534 case 2: 4535 ct = DM_POLYTOPE_SEGMENT; 4536 break; 4537 case 3: 4538 ct = DM_POLYTOPE_TRIANGLE; 4539 break; 4540 case 4: 4541 ct = DM_POLYTOPE_QUADRILATERAL; 4542 break; 4543 default: 4544 break; 4545 } 4546 } 4547 } 4548 *pt = ct; 4549 PetscFunctionReturn(PETSC_SUCCESS); 4550 } 4551 4552 /*@ 4553 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4554 4555 Collective 4556 4557 Input Parameter: 4558 . dm - The `DMPLEX` 4559 4560 Level: developer 4561 4562 Note: 4563 This function is normally called automatically when a cell type is requested. It creates an 4564 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4565 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4566 4567 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4568 4569 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4570 @*/ 4571 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4572 { 4573 DM_Plex *mesh; 4574 DMLabel ctLabel; 4575 PetscInt pStart, pEnd, p; 4576 4577 PetscFunctionBegin; 4578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4579 mesh = (DM_Plex *)dm->data; 4580 PetscCall(DMCreateLabel(dm, "celltype")); 4581 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4582 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4583 PetscCall(PetscFree(mesh->cellTypes)); 4584 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4585 for (p = pStart; p < pEnd; ++p) { 4586 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4587 PetscInt pdepth; 4588 4589 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4590 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4591 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); 4592 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4593 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4594 } 4595 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4596 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4597 PetscFunctionReturn(PETSC_SUCCESS); 4598 } 4599 4600 /*@C 4601 DMPlexGetJoin - Get an array for the join of the set of points 4602 4603 Not Collective 4604 4605 Input Parameters: 4606 + dm - The `DMPLEX` object 4607 . numPoints - The number of input points for the join 4608 - points - The input points 4609 4610 Output Parameters: 4611 + numCoveredPoints - The number of points in the join 4612 - coveredPoints - The points in the join 4613 4614 Level: intermediate 4615 4616 Note: 4617 Currently, this is restricted to a single level join 4618 4619 Fortran Notes: 4620 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4621 4622 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4623 @*/ 4624 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4625 { 4626 DM_Plex *mesh = (DM_Plex *)dm->data; 4627 PetscInt *join[2]; 4628 PetscInt joinSize, i = 0; 4629 PetscInt dof, off, p, c, m; 4630 PetscInt maxSupportSize; 4631 4632 PetscFunctionBegin; 4633 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4634 PetscAssertPointer(points, 3); 4635 PetscAssertPointer(numCoveredPoints, 4); 4636 PetscAssertPointer(coveredPoints, 5); 4637 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4638 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4639 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4640 /* Copy in support of first point */ 4641 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4642 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4643 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4644 /* Check each successive support */ 4645 for (p = 1; p < numPoints; ++p) { 4646 PetscInt newJoinSize = 0; 4647 4648 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4649 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4650 for (c = 0; c < dof; ++c) { 4651 const PetscInt point = mesh->supports[off + c]; 4652 4653 for (m = 0; m < joinSize; ++m) { 4654 if (point == join[i][m]) { 4655 join[1 - i][newJoinSize++] = point; 4656 break; 4657 } 4658 } 4659 } 4660 joinSize = newJoinSize; 4661 i = 1 - i; 4662 } 4663 *numCoveredPoints = joinSize; 4664 *coveredPoints = join[i]; 4665 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4666 PetscFunctionReturn(PETSC_SUCCESS); 4667 } 4668 4669 /*@C 4670 DMPlexRestoreJoin - Restore an array for the join of the set of points 4671 4672 Not Collective 4673 4674 Input Parameters: 4675 + dm - The `DMPLEX` object 4676 . numPoints - The number of input points for the join 4677 - points - The input points 4678 4679 Output Parameters: 4680 + numCoveredPoints - The number of points in the join 4681 - coveredPoints - The points in the join 4682 4683 Level: intermediate 4684 4685 Fortran Notes: 4686 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4687 4688 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4689 @*/ 4690 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4691 { 4692 PetscFunctionBegin; 4693 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4694 if (points) PetscAssertPointer(points, 3); 4695 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4696 PetscAssertPointer(coveredPoints, 5); 4697 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4698 if (numCoveredPoints) *numCoveredPoints = 0; 4699 PetscFunctionReturn(PETSC_SUCCESS); 4700 } 4701 4702 /*@C 4703 DMPlexGetFullJoin - Get an array for the join of the set of points 4704 4705 Not Collective 4706 4707 Input Parameters: 4708 + dm - The `DMPLEX` object 4709 . numPoints - The number of input points for the join 4710 - points - The input points 4711 4712 Output Parameters: 4713 + numCoveredPoints - The number of points in the join 4714 - coveredPoints - The points in the join 4715 4716 Level: intermediate 4717 4718 Fortran Notes: 4719 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4720 4721 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4722 @*/ 4723 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4724 { 4725 PetscInt *offsets, **closures; 4726 PetscInt *join[2]; 4727 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4728 PetscInt p, d, c, m, ms; 4729 4730 PetscFunctionBegin; 4731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4732 PetscAssertPointer(points, 3); 4733 PetscAssertPointer(numCoveredPoints, 4); 4734 PetscAssertPointer(coveredPoints, 5); 4735 4736 PetscCall(DMPlexGetDepth(dm, &depth)); 4737 PetscCall(PetscCalloc1(numPoints, &closures)); 4738 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4739 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4740 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4741 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4742 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4743 4744 for (p = 0; p < numPoints; ++p) { 4745 PetscInt closureSize; 4746 4747 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4748 4749 offsets[p * (depth + 2) + 0] = 0; 4750 for (d = 0; d < depth + 1; ++d) { 4751 PetscInt pStart, pEnd, i; 4752 4753 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4754 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4755 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4756 offsets[p * (depth + 2) + d + 1] = i; 4757 break; 4758 } 4759 } 4760 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4761 } 4762 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); 4763 } 4764 for (d = 0; d < depth + 1; ++d) { 4765 PetscInt dof; 4766 4767 /* Copy in support of first point */ 4768 dof = offsets[d + 1] - offsets[d]; 4769 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4770 /* Check each successive cone */ 4771 for (p = 1; p < numPoints && joinSize; ++p) { 4772 PetscInt newJoinSize = 0; 4773 4774 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4775 for (c = 0; c < dof; ++c) { 4776 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4777 4778 for (m = 0; m < joinSize; ++m) { 4779 if (point == join[i][m]) { 4780 join[1 - i][newJoinSize++] = point; 4781 break; 4782 } 4783 } 4784 } 4785 joinSize = newJoinSize; 4786 i = 1 - i; 4787 } 4788 if (joinSize) break; 4789 } 4790 *numCoveredPoints = joinSize; 4791 *coveredPoints = join[i]; 4792 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4793 PetscCall(PetscFree(closures)); 4794 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4795 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4796 PetscFunctionReturn(PETSC_SUCCESS); 4797 } 4798 4799 /*@C 4800 DMPlexGetMeet - Get an array for the meet of the set of points 4801 4802 Not Collective 4803 4804 Input Parameters: 4805 + dm - The `DMPLEX` object 4806 . numPoints - The number of input points for the meet 4807 - points - The input points 4808 4809 Output Parameters: 4810 + numCoveringPoints - The number of points in the meet 4811 - coveringPoints - The points in the meet 4812 4813 Level: intermediate 4814 4815 Note: 4816 Currently, this is restricted to a single level meet 4817 4818 Fortran Notes: 4819 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4820 4821 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4822 @*/ 4823 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4824 { 4825 DM_Plex *mesh = (DM_Plex *)dm->data; 4826 PetscInt *meet[2]; 4827 PetscInt meetSize, i = 0; 4828 PetscInt dof, off, p, c, m; 4829 PetscInt maxConeSize; 4830 4831 PetscFunctionBegin; 4832 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4833 PetscAssertPointer(points, 3); 4834 PetscAssertPointer(numCoveringPoints, 4); 4835 PetscAssertPointer(coveringPoints, 5); 4836 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4837 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4838 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4839 /* Copy in cone of first point */ 4840 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4841 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4842 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4843 /* Check each successive cone */ 4844 for (p = 1; p < numPoints; ++p) { 4845 PetscInt newMeetSize = 0; 4846 4847 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4848 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4849 for (c = 0; c < dof; ++c) { 4850 const PetscInt point = mesh->cones[off + c]; 4851 4852 for (m = 0; m < meetSize; ++m) { 4853 if (point == meet[i][m]) { 4854 meet[1 - i][newMeetSize++] = point; 4855 break; 4856 } 4857 } 4858 } 4859 meetSize = newMeetSize; 4860 i = 1 - i; 4861 } 4862 *numCoveringPoints = meetSize; 4863 *coveringPoints = meet[i]; 4864 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4865 PetscFunctionReturn(PETSC_SUCCESS); 4866 } 4867 4868 /*@C 4869 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4870 4871 Not Collective 4872 4873 Input Parameters: 4874 + dm - The `DMPLEX` object 4875 . numPoints - The number of input points for the meet 4876 - points - The input points 4877 4878 Output Parameters: 4879 + numCoveredPoints - The number of points in the meet 4880 - coveredPoints - The points in the meet 4881 4882 Level: intermediate 4883 4884 Fortran Notes: 4885 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4886 4887 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4888 @*/ 4889 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4890 { 4891 PetscFunctionBegin; 4892 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4893 if (points) PetscAssertPointer(points, 3); 4894 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4895 PetscAssertPointer(coveredPoints, 5); 4896 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4897 if (numCoveredPoints) *numCoveredPoints = 0; 4898 PetscFunctionReturn(PETSC_SUCCESS); 4899 } 4900 4901 /*@C 4902 DMPlexGetFullMeet - Get an array for the meet of the set of points 4903 4904 Not Collective 4905 4906 Input Parameters: 4907 + dm - The `DMPLEX` object 4908 . numPoints - The number of input points for the meet 4909 - points - The input points 4910 4911 Output Parameters: 4912 + numCoveredPoints - The number of points in the meet 4913 - coveredPoints - The points in the meet 4914 4915 Level: intermediate 4916 4917 Fortran Notes: 4918 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4919 4920 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4921 @*/ 4922 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4923 { 4924 PetscInt *offsets, **closures; 4925 PetscInt *meet[2]; 4926 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4927 PetscInt p, h, c, m, mc; 4928 4929 PetscFunctionBegin; 4930 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4931 PetscAssertPointer(points, 3); 4932 PetscAssertPointer(numCoveredPoints, 4); 4933 PetscAssertPointer(coveredPoints, 5); 4934 4935 PetscCall(DMPlexGetDepth(dm, &height)); 4936 PetscCall(PetscMalloc1(numPoints, &closures)); 4937 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4938 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4939 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4940 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4941 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4942 4943 for (p = 0; p < numPoints; ++p) { 4944 PetscInt closureSize; 4945 4946 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4947 4948 offsets[p * (height + 2) + 0] = 0; 4949 for (h = 0; h < height + 1; ++h) { 4950 PetscInt pStart, pEnd, i; 4951 4952 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4953 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4954 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4955 offsets[p * (height + 2) + h + 1] = i; 4956 break; 4957 } 4958 } 4959 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4960 } 4961 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); 4962 } 4963 for (h = 0; h < height + 1; ++h) { 4964 PetscInt dof; 4965 4966 /* Copy in cone of first point */ 4967 dof = offsets[h + 1] - offsets[h]; 4968 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4969 /* Check each successive cone */ 4970 for (p = 1; p < numPoints && meetSize; ++p) { 4971 PetscInt newMeetSize = 0; 4972 4973 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4974 for (c = 0; c < dof; ++c) { 4975 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4976 4977 for (m = 0; m < meetSize; ++m) { 4978 if (point == meet[i][m]) { 4979 meet[1 - i][newMeetSize++] = point; 4980 break; 4981 } 4982 } 4983 } 4984 meetSize = newMeetSize; 4985 i = 1 - i; 4986 } 4987 if (meetSize) break; 4988 } 4989 *numCoveredPoints = meetSize; 4990 *coveredPoints = meet[i]; 4991 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4992 PetscCall(PetscFree(closures)); 4993 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4994 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4995 PetscFunctionReturn(PETSC_SUCCESS); 4996 } 4997 4998 /*@C 4999 DMPlexEqual - Determine if two `DM` have the same topology 5000 5001 Not Collective 5002 5003 Input Parameters: 5004 + dmA - A `DMPLEX` object 5005 - dmB - A `DMPLEX` object 5006 5007 Output Parameter: 5008 . equal - `PETSC_TRUE` if the topologies are identical 5009 5010 Level: intermediate 5011 5012 Note: 5013 We are not solving graph isomorphism, so we do not permute. 5014 5015 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5016 @*/ 5017 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5018 { 5019 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5020 5021 PetscFunctionBegin; 5022 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5023 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5024 PetscAssertPointer(equal, 3); 5025 5026 *equal = PETSC_FALSE; 5027 PetscCall(DMPlexGetDepth(dmA, &depth)); 5028 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5029 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5030 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5031 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5032 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5033 for (p = pStart; p < pEnd; ++p) { 5034 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5035 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5036 5037 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5038 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5039 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5040 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5041 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5042 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5043 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5044 for (c = 0; c < coneSize; ++c) { 5045 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5046 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5047 } 5048 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5049 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5050 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5051 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5052 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5053 for (s = 0; s < supportSize; ++s) { 5054 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5055 } 5056 } 5057 *equal = PETSC_TRUE; 5058 PetscFunctionReturn(PETSC_SUCCESS); 5059 } 5060 5061 /*@C 5062 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5063 5064 Not Collective 5065 5066 Input Parameters: 5067 + dm - The `DMPLEX` 5068 . cellDim - The cell dimension 5069 - numCorners - The number of vertices on a cell 5070 5071 Output Parameter: 5072 . numFaceVertices - The number of vertices on a face 5073 5074 Level: developer 5075 5076 Note: 5077 Of course this can only work for a restricted set of symmetric shapes 5078 5079 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5080 @*/ 5081 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5082 { 5083 MPI_Comm comm; 5084 5085 PetscFunctionBegin; 5086 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5087 PetscAssertPointer(numFaceVertices, 4); 5088 switch (cellDim) { 5089 case 0: 5090 *numFaceVertices = 0; 5091 break; 5092 case 1: 5093 *numFaceVertices = 1; 5094 break; 5095 case 2: 5096 switch (numCorners) { 5097 case 3: /* triangle */ 5098 *numFaceVertices = 2; /* Edge has 2 vertices */ 5099 break; 5100 case 4: /* quadrilateral */ 5101 *numFaceVertices = 2; /* Edge has 2 vertices */ 5102 break; 5103 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5104 *numFaceVertices = 3; /* Edge has 3 vertices */ 5105 break; 5106 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5107 *numFaceVertices = 3; /* Edge has 3 vertices */ 5108 break; 5109 default: 5110 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5111 } 5112 break; 5113 case 3: 5114 switch (numCorners) { 5115 case 4: /* tetradehdron */ 5116 *numFaceVertices = 3; /* Face has 3 vertices */ 5117 break; 5118 case 6: /* tet cohesive cells */ 5119 *numFaceVertices = 4; /* Face has 4 vertices */ 5120 break; 5121 case 8: /* hexahedron */ 5122 *numFaceVertices = 4; /* Face has 4 vertices */ 5123 break; 5124 case 9: /* tet cohesive Lagrange cells */ 5125 *numFaceVertices = 6; /* Face has 6 vertices */ 5126 break; 5127 case 10: /* quadratic tetrahedron */ 5128 *numFaceVertices = 6; /* Face has 6 vertices */ 5129 break; 5130 case 12: /* hex cohesive Lagrange cells */ 5131 *numFaceVertices = 6; /* Face has 6 vertices */ 5132 break; 5133 case 18: /* quadratic tet cohesive Lagrange cells */ 5134 *numFaceVertices = 6; /* Face has 6 vertices */ 5135 break; 5136 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5137 *numFaceVertices = 9; /* Face has 9 vertices */ 5138 break; 5139 default: 5140 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5141 } 5142 break; 5143 default: 5144 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5145 } 5146 PetscFunctionReturn(PETSC_SUCCESS); 5147 } 5148 5149 /*@ 5150 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5151 5152 Not Collective 5153 5154 Input Parameter: 5155 . dm - The `DMPLEX` object 5156 5157 Output Parameter: 5158 . depthLabel - The `DMLabel` recording point depth 5159 5160 Level: developer 5161 5162 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5163 @*/ 5164 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5165 { 5166 PetscFunctionBegin; 5167 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5168 PetscAssertPointer(depthLabel, 2); 5169 *depthLabel = dm->depthLabel; 5170 PetscFunctionReturn(PETSC_SUCCESS); 5171 } 5172 5173 /*@ 5174 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5175 5176 Not Collective 5177 5178 Input Parameter: 5179 . dm - The `DMPLEX` object 5180 5181 Output Parameter: 5182 . depth - The number of strata (breadth first levels) in the DAG 5183 5184 Level: developer 5185 5186 Notes: 5187 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5188 5189 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5190 5191 An empty mesh gives -1. 5192 5193 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5194 @*/ 5195 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5196 { 5197 DM_Plex *mesh = (DM_Plex *)dm->data; 5198 DMLabel label; 5199 PetscInt d = 0; 5200 5201 PetscFunctionBegin; 5202 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5203 PetscAssertPointer(depth, 2); 5204 if (mesh->tr) { 5205 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5206 } else { 5207 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5208 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5209 *depth = d - 1; 5210 } 5211 PetscFunctionReturn(PETSC_SUCCESS); 5212 } 5213 5214 /*@ 5215 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5216 5217 Not Collective 5218 5219 Input Parameters: 5220 + dm - The `DMPLEX` object 5221 - depth - The requested depth 5222 5223 Output Parameters: 5224 + start - The first point at this `depth` 5225 - end - One beyond the last point at this `depth` 5226 5227 Level: developer 5228 5229 Notes: 5230 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5231 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5232 higher dimension, e.g., "edges". 5233 5234 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5235 @*/ 5236 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5237 { 5238 DM_Plex *mesh = (DM_Plex *)dm->data; 5239 DMLabel label; 5240 PetscInt pStart, pEnd; 5241 5242 PetscFunctionBegin; 5243 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5244 if (start) { 5245 PetscAssertPointer(start, 3); 5246 *start = 0; 5247 } 5248 if (end) { 5249 PetscAssertPointer(end, 4); 5250 *end = 0; 5251 } 5252 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5253 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5254 if (depth < 0) { 5255 if (start) *start = pStart; 5256 if (end) *end = pEnd; 5257 PetscFunctionReturn(PETSC_SUCCESS); 5258 } 5259 if (mesh->tr) { 5260 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5261 } else { 5262 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5263 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5264 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5265 } 5266 PetscFunctionReturn(PETSC_SUCCESS); 5267 } 5268 5269 /*@ 5270 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5271 5272 Not Collective 5273 5274 Input Parameters: 5275 + dm - The `DMPLEX` object 5276 - height - The requested height 5277 5278 Output Parameters: 5279 + start - The first point at this `height` 5280 - end - One beyond the last point at this `height` 5281 5282 Level: developer 5283 5284 Notes: 5285 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5286 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5287 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5288 5289 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5290 @*/ 5291 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5292 { 5293 DMLabel label; 5294 PetscInt depth, pStart, pEnd; 5295 5296 PetscFunctionBegin; 5297 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5298 if (start) { 5299 PetscAssertPointer(start, 3); 5300 *start = 0; 5301 } 5302 if (end) { 5303 PetscAssertPointer(end, 4); 5304 *end = 0; 5305 } 5306 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5307 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5308 if (height < 0) { 5309 if (start) *start = pStart; 5310 if (end) *end = pEnd; 5311 PetscFunctionReturn(PETSC_SUCCESS); 5312 } 5313 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5314 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5315 else PetscCall(DMGetDimension(dm, &depth)); 5316 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5317 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5318 PetscFunctionReturn(PETSC_SUCCESS); 5319 } 5320 5321 /*@ 5322 DMPlexGetPointDepth - Get the `depth` of a given point 5323 5324 Not Collective 5325 5326 Input Parameters: 5327 + dm - The `DMPLEX` object 5328 - point - The point 5329 5330 Output Parameter: 5331 . depth - The depth of the `point` 5332 5333 Level: intermediate 5334 5335 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5336 @*/ 5337 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5338 { 5339 PetscFunctionBegin; 5340 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5341 PetscAssertPointer(depth, 3); 5342 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5343 PetscFunctionReturn(PETSC_SUCCESS); 5344 } 5345 5346 /*@ 5347 DMPlexGetPointHeight - Get the `height` of a given point 5348 5349 Not Collective 5350 5351 Input Parameters: 5352 + dm - The `DMPLEX` object 5353 - point - The point 5354 5355 Output Parameter: 5356 . height - The height of the `point` 5357 5358 Level: intermediate 5359 5360 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5361 @*/ 5362 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5363 { 5364 PetscInt n, pDepth; 5365 5366 PetscFunctionBegin; 5367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5368 PetscAssertPointer(height, 3); 5369 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5370 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5371 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5372 PetscFunctionReturn(PETSC_SUCCESS); 5373 } 5374 5375 /*@ 5376 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5377 5378 Not Collective 5379 5380 Input Parameter: 5381 . dm - The `DMPLEX` object 5382 5383 Output Parameter: 5384 . celltypeLabel - The `DMLabel` recording cell polytope type 5385 5386 Level: developer 5387 5388 Note: 5389 This function will trigger automatica computation of cell types. This can be disabled by calling 5390 `DMCreateLabel`(dm, "celltype") beforehand. 5391 5392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5393 @*/ 5394 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5395 { 5396 PetscFunctionBegin; 5397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5398 PetscAssertPointer(celltypeLabel, 2); 5399 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5400 *celltypeLabel = dm->celltypeLabel; 5401 PetscFunctionReturn(PETSC_SUCCESS); 5402 } 5403 5404 /*@ 5405 DMPlexGetCellType - Get the polytope type of a given cell 5406 5407 Not Collective 5408 5409 Input Parameters: 5410 + dm - The `DMPLEX` object 5411 - cell - The cell 5412 5413 Output Parameter: 5414 . celltype - The polytope type of the cell 5415 5416 Level: intermediate 5417 5418 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5419 @*/ 5420 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5421 { 5422 DM_Plex *mesh = (DM_Plex *)dm->data; 5423 DMLabel label; 5424 PetscInt ct; 5425 5426 PetscFunctionBegin; 5427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5428 PetscAssertPointer(celltype, 3); 5429 if (mesh->tr) { 5430 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5431 } else { 5432 PetscInt pStart, pEnd; 5433 5434 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5435 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5436 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5437 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5438 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5439 for (PetscInt p = pStart; p < pEnd; p++) { 5440 PetscCall(DMLabelGetValue(label, p, &ct)); 5441 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5442 } 5443 } 5444 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5445 if (PetscDefined(USE_DEBUG)) { 5446 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5447 PetscCall(DMLabelGetValue(label, cell, &ct)); 5448 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5449 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5450 } 5451 } 5452 PetscFunctionReturn(PETSC_SUCCESS); 5453 } 5454 5455 /*@ 5456 DMPlexSetCellType - Set the polytope type of a given cell 5457 5458 Not Collective 5459 5460 Input Parameters: 5461 + dm - The `DMPLEX` object 5462 . cell - The cell 5463 - celltype - The polytope type of the cell 5464 5465 Level: advanced 5466 5467 Note: 5468 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5469 is executed. This function will override the computed type. However, if automatic classification will not succeed 5470 and a user wants to manually specify all types, the classification must be disabled by calling 5471 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5472 5473 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5474 @*/ 5475 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5476 { 5477 DM_Plex *mesh = (DM_Plex *)dm->data; 5478 DMLabel label; 5479 PetscInt pStart, pEnd; 5480 5481 PetscFunctionBegin; 5482 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5483 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5484 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5485 PetscCall(DMLabelSetValue(label, cell, celltype)); 5486 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5487 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5488 PetscFunctionReturn(PETSC_SUCCESS); 5489 } 5490 5491 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5492 { 5493 PetscSection section, s; 5494 Mat m; 5495 PetscInt maxHeight; 5496 const char *prefix; 5497 5498 PetscFunctionBegin; 5499 PetscCall(DMClone(dm, cdm)); 5500 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5501 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5502 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5503 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5504 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5505 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5506 PetscCall(DMSetLocalSection(*cdm, section)); 5507 PetscCall(PetscSectionDestroy(§ion)); 5508 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5509 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5510 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5511 PetscCall(PetscSectionDestroy(&s)); 5512 PetscCall(MatDestroy(&m)); 5513 5514 PetscCall(DMSetNumFields(*cdm, 1)); 5515 PetscCall(DMCreateDS(*cdm)); 5516 (*cdm)->cloneOpts = PETSC_TRUE; 5517 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5518 PetscFunctionReturn(PETSC_SUCCESS); 5519 } 5520 5521 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5522 { 5523 Vec coordsLocal, cellCoordsLocal; 5524 DM coordsDM, cellCoordsDM; 5525 5526 PetscFunctionBegin; 5527 *field = NULL; 5528 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5529 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5530 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5531 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5532 if (coordsLocal && coordsDM) { 5533 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5534 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5535 } 5536 PetscFunctionReturn(PETSC_SUCCESS); 5537 } 5538 5539 /*@C 5540 DMPlexGetConeSection - Return a section which describes the layout of cone data 5541 5542 Not Collective 5543 5544 Input Parameter: 5545 . dm - The `DMPLEX` object 5546 5547 Output Parameter: 5548 . section - The `PetscSection` object 5549 5550 Level: developer 5551 5552 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5553 @*/ 5554 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5555 { 5556 DM_Plex *mesh = (DM_Plex *)dm->data; 5557 5558 PetscFunctionBegin; 5559 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5560 if (section) *section = mesh->coneSection; 5561 PetscFunctionReturn(PETSC_SUCCESS); 5562 } 5563 5564 /*@C 5565 DMPlexGetSupportSection - Return a section which describes the layout of support data 5566 5567 Not Collective 5568 5569 Input Parameter: 5570 . dm - The `DMPLEX` object 5571 5572 Output Parameter: 5573 . section - The `PetscSection` object 5574 5575 Level: developer 5576 5577 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5578 @*/ 5579 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5580 { 5581 DM_Plex *mesh = (DM_Plex *)dm->data; 5582 5583 PetscFunctionBegin; 5584 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5585 if (section) *section = mesh->supportSection; 5586 PetscFunctionReturn(PETSC_SUCCESS); 5587 } 5588 5589 /*@C 5590 DMPlexGetCones - Return cone data 5591 5592 Not Collective 5593 5594 Input Parameter: 5595 . dm - The `DMPLEX` object 5596 5597 Output Parameter: 5598 . cones - The cone for each point 5599 5600 Level: developer 5601 5602 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5603 @*/ 5604 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5605 { 5606 DM_Plex *mesh = (DM_Plex *)dm->data; 5607 5608 PetscFunctionBegin; 5609 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5610 if (cones) *cones = mesh->cones; 5611 PetscFunctionReturn(PETSC_SUCCESS); 5612 } 5613 5614 /*@C 5615 DMPlexGetConeOrientations - Return cone orientation data 5616 5617 Not Collective 5618 5619 Input Parameter: 5620 . dm - The `DMPLEX` object 5621 5622 Output Parameter: 5623 . coneOrientations - The array of cone orientations for all points 5624 5625 Level: developer 5626 5627 Notes: 5628 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5629 5630 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5631 5632 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5633 @*/ 5634 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5635 { 5636 DM_Plex *mesh = (DM_Plex *)dm->data; 5637 5638 PetscFunctionBegin; 5639 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5640 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5641 PetscFunctionReturn(PETSC_SUCCESS); 5642 } 5643 5644 /******************************** FEM Support **********************************/ 5645 5646 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5647 { 5648 PetscInt depth; 5649 5650 PetscFunctionBegin; 5651 PetscCall(DMPlexGetDepth(plex, &depth)); 5652 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5653 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5654 PetscFunctionReturn(PETSC_SUCCESS); 5655 } 5656 5657 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5658 { 5659 PetscInt depth; 5660 5661 PetscFunctionBegin; 5662 PetscCall(DMPlexGetDepth(plex, &depth)); 5663 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5664 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5665 PetscFunctionReturn(PETSC_SUCCESS); 5666 } 5667 5668 /* 5669 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5670 representing a line in the section. 5671 */ 5672 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous) 5673 { 5674 PetscObject obj; 5675 PetscClassId id; 5676 PetscFE fe = NULL; 5677 5678 PetscFunctionBeginHot; 5679 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5680 PetscCall(DMGetField(dm, field, NULL, &obj)); 5681 PetscCall(PetscObjectGetClassId(obj, &id)); 5682 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5683 5684 if (!fe) { 5685 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5686 /* An order k SEM disc has k-1 dofs on an edge */ 5687 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5688 *k = *k / *Nc + 1; 5689 } else { 5690 PetscInt dual_space_size, dim; 5691 PetscDualSpace dual_space; 5692 PetscCall(DMGetDimension(dm, &dim)); 5693 PetscCall(PetscFEGetDualSpace(fe, &dual_space)); 5694 PetscCall(PetscDualSpaceGetDimension(dual_space, &dual_space_size)); 5695 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5696 PetscCall(PetscDualSpaceLagrangeGetContinuity(dual_space, continuous)); 5697 } 5698 PetscFunctionReturn(PETSC_SUCCESS); 5699 } 5700 5701 /*@ 5702 5703 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5704 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5705 section provided (or the section of the `DM`). 5706 5707 Input Parameters: 5708 + dm - The `DM` 5709 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5710 - section - The `PetscSection` to reorder, or `NULL` for the default section 5711 5712 Example: 5713 A typical interpolated single-quad mesh might order points as 5714 .vb 5715 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5716 5717 v4 -- e6 -- v3 5718 | | 5719 e7 c0 e8 5720 | | 5721 v1 -- e5 -- v2 5722 .ve 5723 5724 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5725 dofs in the order of points, e.g., 5726 .vb 5727 c0 -> [0,1,2,3] 5728 v1 -> [4] 5729 ... 5730 e5 -> [8, 9] 5731 .ve 5732 5733 which corresponds to the dofs 5734 .vb 5735 6 10 11 7 5736 13 2 3 15 5737 12 0 1 14 5738 4 8 9 5 5739 .ve 5740 5741 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5742 .vb 5743 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5744 .ve 5745 5746 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5747 .vb 5748 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5749 .ve 5750 5751 Level: developer 5752 5753 Notes: 5754 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5755 degree of the basis. 5756 5757 This is required to run with libCEED. 5758 5759 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5760 @*/ 5761 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5762 { 5763 DMLabel label; 5764 PetscInt dim, depth = -1, eStart = -1, Nf; 5765 PetscBool continuous = PETSC_TRUE; 5766 5767 PetscFunctionBegin; 5768 PetscCall(DMGetDimension(dm, &dim)); 5769 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5770 if (point < 0) { 5771 PetscInt sStart, sEnd; 5772 5773 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5774 point = sEnd - sStart ? sStart : point; 5775 } 5776 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5777 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5778 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5779 if (depth == 1) { 5780 eStart = point; 5781 } else if (depth == dim) { 5782 const PetscInt *cone; 5783 5784 PetscCall(DMPlexGetCone(dm, point, &cone)); 5785 if (dim == 2) eStart = cone[0]; 5786 else if (dim == 3) { 5787 const PetscInt *cone2; 5788 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5789 eStart = cone2[0]; 5790 } 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); 5791 } 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); 5792 5793 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5794 for (PetscInt d = 1; d <= dim; d++) { 5795 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5796 PetscInt *perm; 5797 5798 for (f = 0; f < Nf; ++f) { 5799 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5800 size += PetscPowInt(k + 1, d) * Nc; 5801 } 5802 PetscCall(PetscMalloc1(size, &perm)); 5803 for (f = 0; f < Nf; ++f) { 5804 switch (d) { 5805 case 1: 5806 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5807 /* 5808 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5809 We want [ vtx0; edge of length k-1; vtx1 ] 5810 */ 5811 if (continuous) { 5812 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5813 for (i = 0; i < k - 1; i++) 5814 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5815 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5816 foffset = offset; 5817 } else { 5818 for (i = offset; i < size; i++) perm[i] = i - offset + foffset; 5819 foffset = offset = size; 5820 } 5821 break; 5822 case 2: 5823 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5824 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5825 /* The SEM order is 5826 5827 v_lb, {e_b}, v_rb, 5828 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5829 v_lt, reverse {e_t}, v_rt 5830 */ 5831 if (continuous) { 5832 const PetscInt of = 0; 5833 const PetscInt oeb = of + PetscSqr(k - 1); 5834 const PetscInt oer = oeb + (k - 1); 5835 const PetscInt oet = oer + (k - 1); 5836 const PetscInt oel = oet + (k - 1); 5837 const PetscInt ovlb = oel + (k - 1); 5838 const PetscInt ovrb = ovlb + 1; 5839 const PetscInt ovrt = ovrb + 1; 5840 const PetscInt ovlt = ovrt + 1; 5841 PetscInt o; 5842 5843 /* bottom */ 5844 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5845 for (o = oeb; o < oer; ++o) 5846 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5847 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5848 /* middle */ 5849 for (i = 0; i < k - 1; ++i) { 5850 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5851 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5852 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5853 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5854 } 5855 /* top */ 5856 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5857 for (o = oel - 1; o >= oet; --o) 5858 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5859 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5860 foffset = offset; 5861 } else { 5862 for (i = offset; i < size; i++) perm[i] = i - offset + foffset; 5863 foffset = offset = size; 5864 } 5865 break; 5866 case 3: 5867 /* The original hex closure is 5868 5869 {c, 5870 f_b, f_t, f_f, f_b, f_r, f_l, 5871 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5872 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5873 */ 5874 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5875 /* The SEM order is 5876 Bottom Slice 5877 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5878 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5879 v_blb, {e_bb}, v_brb, 5880 5881 Middle Slice (j) 5882 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5883 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5884 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5885 5886 Top Slice 5887 v_tlf, {e_tf}, v_trf, 5888 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5889 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5890 */ 5891 if (continuous) { 5892 const PetscInt oc = 0; 5893 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5894 const PetscInt oft = ofb + PetscSqr(k - 1); 5895 const PetscInt off = oft + PetscSqr(k - 1); 5896 const PetscInt ofk = off + PetscSqr(k - 1); 5897 const PetscInt ofr = ofk + PetscSqr(k - 1); 5898 const PetscInt ofl = ofr + PetscSqr(k - 1); 5899 const PetscInt oebl = ofl + PetscSqr(k - 1); 5900 const PetscInt oebb = oebl + (k - 1); 5901 const PetscInt oebr = oebb + (k - 1); 5902 const PetscInt oebf = oebr + (k - 1); 5903 const PetscInt oetf = oebf + (k - 1); 5904 const PetscInt oetr = oetf + (k - 1); 5905 const PetscInt oetb = oetr + (k - 1); 5906 const PetscInt oetl = oetb + (k - 1); 5907 const PetscInt oerf = oetl + (k - 1); 5908 const PetscInt oelf = oerf + (k - 1); 5909 const PetscInt oelb = oelf + (k - 1); 5910 const PetscInt oerb = oelb + (k - 1); 5911 const PetscInt ovblf = oerb + (k - 1); 5912 const PetscInt ovblb = ovblf + 1; 5913 const PetscInt ovbrb = ovblb + 1; 5914 const PetscInt ovbrf = ovbrb + 1; 5915 const PetscInt ovtlf = ovbrf + 1; 5916 const PetscInt ovtrf = ovtlf + 1; 5917 const PetscInt ovtrb = ovtrf + 1; 5918 const PetscInt ovtlb = ovtrb + 1; 5919 PetscInt o, n; 5920 5921 /* Bottom Slice */ 5922 /* bottom */ 5923 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5924 for (o = oetf - 1; o >= oebf; --o) 5925 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5926 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5927 /* middle */ 5928 for (i = 0; i < k - 1; ++i) { 5929 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5930 for (n = 0; n < k - 1; ++n) { 5931 o = ofb + n * (k - 1) + i; 5932 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5933 } 5934 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5935 } 5936 /* top */ 5937 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5938 for (o = oebb; o < oebr; ++o) 5939 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5940 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5941 5942 /* Middle Slice */ 5943 for (j = 0; j < k - 1; ++j) { 5944 /* bottom */ 5945 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5946 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5947 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5948 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5949 /* middle */ 5950 for (i = 0; i < k - 1; ++i) { 5951 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5952 for (n = 0; n < k - 1; ++n) 5953 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5954 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5955 } 5956 /* top */ 5957 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5958 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5959 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5960 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5961 } 5962 5963 /* Top Slice */ 5964 /* bottom */ 5965 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5966 for (o = oetf; o < oetr; ++o) 5967 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5968 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5969 /* middle */ 5970 for (i = 0; i < k - 1; ++i) { 5971 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5972 for (n = 0; n < k - 1; ++n) 5973 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5974 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5975 } 5976 /* top */ 5977 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5978 for (o = oetl - 1; o >= oetb; --o) 5979 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5980 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5981 5982 foffset = offset; 5983 } else { 5984 for (i = offset; i < size; i++) perm[i] = i - offset + foffset; 5985 foffset = offset = size; 5986 } 5987 break; 5988 default: 5989 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5990 } 5991 } 5992 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5993 /* Check permutation */ 5994 { 5995 PetscInt *check; 5996 5997 PetscCall(PetscMalloc1(size, &check)); 5998 for (i = 0; i < size; ++i) { 5999 check[i] = -1; 6000 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6001 } 6002 for (i = 0; i < size; ++i) check[perm[i]] = i; 6003 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6004 PetscCall(PetscFree(check)); 6005 } 6006 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6007 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6008 PetscInt *loc_perm; 6009 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6010 for (PetscInt i = 0; i < size; i++) { 6011 loc_perm[i] = perm[i]; 6012 loc_perm[size + i] = size + perm[i]; 6013 } 6014 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6015 } 6016 } 6017 PetscFunctionReturn(PETSC_SUCCESS); 6018 } 6019 6020 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6021 { 6022 PetscDS prob; 6023 PetscInt depth, Nf, h; 6024 DMLabel label; 6025 6026 PetscFunctionBeginHot; 6027 PetscCall(DMGetDS(dm, &prob)); 6028 Nf = prob->Nf; 6029 label = dm->depthLabel; 6030 *dspace = NULL; 6031 if (field < Nf) { 6032 PetscObject disc = prob->disc[field]; 6033 6034 if (disc->classid == PETSCFE_CLASSID) { 6035 PetscDualSpace dsp; 6036 6037 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6038 PetscCall(DMLabelGetNumValues(label, &depth)); 6039 PetscCall(DMLabelGetValue(label, point, &h)); 6040 h = depth - 1 - h; 6041 if (h) { 6042 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6043 } else { 6044 *dspace = dsp; 6045 } 6046 } 6047 } 6048 PetscFunctionReturn(PETSC_SUCCESS); 6049 } 6050 6051 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6052 { 6053 PetscScalar *array; 6054 const PetscScalar *vArray; 6055 const PetscInt *cone, *coneO; 6056 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6057 6058 PetscFunctionBeginHot; 6059 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6060 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6061 PetscCall(DMPlexGetCone(dm, point, &cone)); 6062 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6063 if (!values || !*values) { 6064 if ((point >= pStart) && (point < pEnd)) { 6065 PetscInt dof; 6066 6067 PetscCall(PetscSectionGetDof(section, point, &dof)); 6068 size += dof; 6069 } 6070 for (p = 0; p < numPoints; ++p) { 6071 const PetscInt cp = cone[p]; 6072 PetscInt dof; 6073 6074 if ((cp < pStart) || (cp >= pEnd)) continue; 6075 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6076 size += dof; 6077 } 6078 if (!values) { 6079 if (csize) *csize = size; 6080 PetscFunctionReturn(PETSC_SUCCESS); 6081 } 6082 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6083 } else { 6084 array = *values; 6085 } 6086 size = 0; 6087 PetscCall(VecGetArrayRead(v, &vArray)); 6088 if ((point >= pStart) && (point < pEnd)) { 6089 PetscInt dof, off, d; 6090 const PetscScalar *varr; 6091 6092 PetscCall(PetscSectionGetDof(section, point, &dof)); 6093 PetscCall(PetscSectionGetOffset(section, point, &off)); 6094 varr = &vArray[off]; 6095 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6096 size += dof; 6097 } 6098 for (p = 0; p < numPoints; ++p) { 6099 const PetscInt cp = cone[p]; 6100 PetscInt o = coneO[p]; 6101 PetscInt dof, off, d; 6102 const PetscScalar *varr; 6103 6104 if ((cp < pStart) || (cp >= pEnd)) continue; 6105 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6106 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6107 varr = &vArray[off]; 6108 if (o >= 0) { 6109 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6110 } else { 6111 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6112 } 6113 size += dof; 6114 } 6115 PetscCall(VecRestoreArrayRead(v, &vArray)); 6116 if (!*values) { 6117 if (csize) *csize = size; 6118 *values = array; 6119 } else { 6120 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6121 *csize = size; 6122 } 6123 PetscFunctionReturn(PETSC_SUCCESS); 6124 } 6125 6126 /* Compress out points not in the section */ 6127 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6128 { 6129 const PetscInt np = *numPoints; 6130 PetscInt pStart, pEnd, p, q; 6131 6132 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6133 for (p = 0, q = 0; p < np; ++p) { 6134 const PetscInt r = points[p * 2]; 6135 if ((r >= pStart) && (r < pEnd)) { 6136 points[q * 2] = r; 6137 points[q * 2 + 1] = points[p * 2 + 1]; 6138 ++q; 6139 } 6140 } 6141 *numPoints = q; 6142 return PETSC_SUCCESS; 6143 } 6144 6145 /* Compressed closure does not apply closure permutation */ 6146 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6147 { 6148 const PetscInt *cla = NULL; 6149 PetscInt np, *pts = NULL; 6150 6151 PetscFunctionBeginHot; 6152 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6153 if (!ornt && *clPoints) { 6154 PetscInt dof, off; 6155 6156 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6157 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6158 PetscCall(ISGetIndices(*clPoints, &cla)); 6159 np = dof / 2; 6160 pts = (PetscInt *)&cla[off]; 6161 } else { 6162 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6163 PetscCall(CompressPoints_Private(section, &np, pts)); 6164 } 6165 *numPoints = np; 6166 *points = pts; 6167 *clp = cla; 6168 PetscFunctionReturn(PETSC_SUCCESS); 6169 } 6170 6171 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6172 { 6173 PetscFunctionBeginHot; 6174 if (!*clPoints) { 6175 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6176 } else { 6177 PetscCall(ISRestoreIndices(*clPoints, clp)); 6178 } 6179 *numPoints = 0; 6180 *points = NULL; 6181 *clSec = NULL; 6182 *clPoints = NULL; 6183 *clp = NULL; 6184 PetscFunctionReturn(PETSC_SUCCESS); 6185 } 6186 6187 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6188 { 6189 PetscInt offset = 0, p; 6190 const PetscInt **perms = NULL; 6191 const PetscScalar **flips = NULL; 6192 6193 PetscFunctionBeginHot; 6194 *size = 0; 6195 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6196 for (p = 0; p < numPoints; p++) { 6197 const PetscInt point = points[2 * p]; 6198 const PetscInt *perm = perms ? perms[p] : NULL; 6199 const PetscScalar *flip = flips ? flips[p] : NULL; 6200 PetscInt dof, off, d; 6201 const PetscScalar *varr; 6202 6203 PetscCall(PetscSectionGetDof(section, point, &dof)); 6204 PetscCall(PetscSectionGetOffset(section, point, &off)); 6205 varr = &vArray[off]; 6206 if (clperm) { 6207 if (perm) { 6208 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6209 } else { 6210 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6211 } 6212 if (flip) { 6213 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6214 } 6215 } else { 6216 if (perm) { 6217 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6218 } else { 6219 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6220 } 6221 if (flip) { 6222 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6223 } 6224 } 6225 offset += dof; 6226 } 6227 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6228 *size = offset; 6229 PetscFunctionReturn(PETSC_SUCCESS); 6230 } 6231 6232 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[]) 6233 { 6234 PetscInt offset = 0, f; 6235 6236 PetscFunctionBeginHot; 6237 *size = 0; 6238 for (f = 0; f < numFields; ++f) { 6239 PetscInt p; 6240 const PetscInt **perms = NULL; 6241 const PetscScalar **flips = NULL; 6242 6243 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6244 for (p = 0; p < numPoints; p++) { 6245 const PetscInt point = points[2 * p]; 6246 PetscInt fdof, foff, b; 6247 const PetscScalar *varr; 6248 const PetscInt *perm = perms ? perms[p] : NULL; 6249 const PetscScalar *flip = flips ? flips[p] : NULL; 6250 6251 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6252 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6253 varr = &vArray[foff]; 6254 if (clperm) { 6255 if (perm) { 6256 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6257 } else { 6258 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6259 } 6260 if (flip) { 6261 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6262 } 6263 } else { 6264 if (perm) { 6265 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6266 } else { 6267 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6268 } 6269 if (flip) { 6270 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6271 } 6272 } 6273 offset += fdof; 6274 } 6275 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6276 } 6277 *size = offset; 6278 PetscFunctionReturn(PETSC_SUCCESS); 6279 } 6280 6281 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6282 { 6283 PetscSection clSection; 6284 IS clPoints; 6285 PetscInt *points = NULL; 6286 const PetscInt *clp, *perm = NULL; 6287 PetscInt depth, numFields, numPoints, asize; 6288 6289 PetscFunctionBeginHot; 6290 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6291 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6292 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6293 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6294 PetscCall(DMPlexGetDepth(dm, &depth)); 6295 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6296 if (depth == 1 && numFields < 2) { 6297 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6298 PetscFunctionReturn(PETSC_SUCCESS); 6299 } 6300 /* Get points */ 6301 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6302 /* Get sizes */ 6303 asize = 0; 6304 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6305 PetscInt dof; 6306 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6307 asize += dof; 6308 } 6309 if (values) { 6310 const PetscScalar *vArray; 6311 PetscInt size; 6312 6313 if (*values) { 6314 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); 6315 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6316 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6317 PetscCall(VecGetArrayRead(v, &vArray)); 6318 /* Get values */ 6319 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6320 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6321 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6322 /* Cleanup array */ 6323 PetscCall(VecRestoreArrayRead(v, &vArray)); 6324 } 6325 if (csize) *csize = asize; 6326 /* Cleanup points */ 6327 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6328 PetscFunctionReturn(PETSC_SUCCESS); 6329 } 6330 6331 /*@C 6332 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6333 6334 Not collective 6335 6336 Input Parameters: 6337 + dm - The `DM` 6338 . section - The section describing the layout in `v`, or `NULL` to use the default section 6339 . v - The local vector 6340 - point - The point in the `DM` 6341 6342 Input/Output Parameters: 6343 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6344 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6345 if the user provided `NULL`, it is a borrowed array and should not be freed 6346 6347 Level: intermediate 6348 6349 Notes: 6350 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6351 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6352 assembly function, and a user may already have allocated storage for this operation. 6353 6354 A typical use could be 6355 .vb 6356 values = NULL; 6357 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6358 for (cl = 0; cl < clSize; ++cl) { 6359 <Compute on closure> 6360 } 6361 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6362 .ve 6363 or 6364 .vb 6365 PetscMalloc1(clMaxSize, &values); 6366 for (p = pStart; p < pEnd; ++p) { 6367 clSize = clMaxSize; 6368 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6369 for (cl = 0; cl < clSize; ++cl) { 6370 <Compute on closure> 6371 } 6372 } 6373 PetscFree(values); 6374 .ve 6375 6376 Fortran Notes: 6377 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6378 6379 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6380 @*/ 6381 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6382 { 6383 PetscFunctionBeginHot; 6384 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6385 PetscFunctionReturn(PETSC_SUCCESS); 6386 } 6387 6388 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6389 { 6390 DMLabel depthLabel; 6391 PetscSection clSection; 6392 IS clPoints; 6393 PetscScalar *array; 6394 const PetscScalar *vArray; 6395 PetscInt *points = NULL; 6396 const PetscInt *clp, *perm = NULL; 6397 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6398 6399 PetscFunctionBeginHot; 6400 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6401 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6402 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6403 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6404 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6405 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6406 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6407 if (mdepth == 1 && numFields < 2) { 6408 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6409 PetscFunctionReturn(PETSC_SUCCESS); 6410 } 6411 /* Get points */ 6412 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6413 for (clsize = 0, p = 0; p < Np; p++) { 6414 PetscInt dof; 6415 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6416 clsize += dof; 6417 } 6418 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6419 /* Filter points */ 6420 for (p = 0; p < numPoints * 2; p += 2) { 6421 PetscInt dep; 6422 6423 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6424 if (dep != depth) continue; 6425 points[Np * 2 + 0] = points[p]; 6426 points[Np * 2 + 1] = points[p + 1]; 6427 ++Np; 6428 } 6429 /* Get array */ 6430 if (!values || !*values) { 6431 PetscInt asize = 0, dof; 6432 6433 for (p = 0; p < Np * 2; p += 2) { 6434 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6435 asize += dof; 6436 } 6437 if (!values) { 6438 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6439 if (csize) *csize = asize; 6440 PetscFunctionReturn(PETSC_SUCCESS); 6441 } 6442 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6443 } else { 6444 array = *values; 6445 } 6446 PetscCall(VecGetArrayRead(v, &vArray)); 6447 /* Get values */ 6448 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6449 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6450 /* Cleanup points */ 6451 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6452 /* Cleanup array */ 6453 PetscCall(VecRestoreArrayRead(v, &vArray)); 6454 if (!*values) { 6455 if (csize) *csize = size; 6456 *values = array; 6457 } else { 6458 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6459 *csize = size; 6460 } 6461 PetscFunctionReturn(PETSC_SUCCESS); 6462 } 6463 6464 /*@C 6465 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6466 6467 Not collective 6468 6469 Input Parameters: 6470 + dm - The `DM` 6471 . section - The section describing the layout in `v`, or `NULL` to use the default section 6472 . v - The local vector 6473 . point - The point in the `DM` 6474 . csize - The number of values in the closure, or `NULL` 6475 - values - The array of values, which is a borrowed array and should not be freed 6476 6477 Level: intermediate 6478 6479 Note: 6480 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6481 6482 Fortran Notes: 6483 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6484 6485 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6486 @*/ 6487 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6488 { 6489 PetscInt size = 0; 6490 6491 PetscFunctionBegin; 6492 /* Should work without recalculating size */ 6493 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6494 *values = NULL; 6495 PetscFunctionReturn(PETSC_SUCCESS); 6496 } 6497 6498 static inline void add(PetscScalar *x, PetscScalar y) 6499 { 6500 *x += y; 6501 } 6502 static inline void insert(PetscScalar *x, PetscScalar y) 6503 { 6504 *x = y; 6505 } 6506 6507 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[]) 6508 { 6509 PetscInt cdof; /* The number of constraints on this point */ 6510 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6511 PetscScalar *a; 6512 PetscInt off, cind = 0, k; 6513 6514 PetscFunctionBegin; 6515 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6516 PetscCall(PetscSectionGetOffset(section, point, &off)); 6517 a = &array[off]; 6518 if (!cdof || setBC) { 6519 if (clperm) { 6520 if (perm) { 6521 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6522 } else { 6523 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6524 } 6525 } else { 6526 if (perm) { 6527 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6528 } else { 6529 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6530 } 6531 } 6532 } else { 6533 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6534 if (clperm) { 6535 if (perm) { 6536 for (k = 0; k < dof; ++k) { 6537 if ((cind < cdof) && (k == cdofs[cind])) { 6538 ++cind; 6539 continue; 6540 } 6541 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6542 } 6543 } else { 6544 for (k = 0; k < dof; ++k) { 6545 if ((cind < cdof) && (k == cdofs[cind])) { 6546 ++cind; 6547 continue; 6548 } 6549 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6550 } 6551 } 6552 } else { 6553 if (perm) { 6554 for (k = 0; k < dof; ++k) { 6555 if ((cind < cdof) && (k == cdofs[cind])) { 6556 ++cind; 6557 continue; 6558 } 6559 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6560 } 6561 } else { 6562 for (k = 0; k < dof; ++k) { 6563 if ((cind < cdof) && (k == cdofs[cind])) { 6564 ++cind; 6565 continue; 6566 } 6567 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6568 } 6569 } 6570 } 6571 } 6572 PetscFunctionReturn(PETSC_SUCCESS); 6573 } 6574 6575 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[]) 6576 { 6577 PetscInt cdof; /* The number of constraints on this point */ 6578 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6579 PetscScalar *a; 6580 PetscInt off, cind = 0, k; 6581 6582 PetscFunctionBegin; 6583 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6584 PetscCall(PetscSectionGetOffset(section, point, &off)); 6585 a = &array[off]; 6586 if (cdof) { 6587 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6588 if (clperm) { 6589 if (perm) { 6590 for (k = 0; k < dof; ++k) { 6591 if ((cind < cdof) && (k == cdofs[cind])) { 6592 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6593 cind++; 6594 } 6595 } 6596 } else { 6597 for (k = 0; k < dof; ++k) { 6598 if ((cind < cdof) && (k == cdofs[cind])) { 6599 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6600 cind++; 6601 } 6602 } 6603 } 6604 } else { 6605 if (perm) { 6606 for (k = 0; k < dof; ++k) { 6607 if ((cind < cdof) && (k == cdofs[cind])) { 6608 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6609 cind++; 6610 } 6611 } 6612 } else { 6613 for (k = 0; k < dof; ++k) { 6614 if ((cind < cdof) && (k == cdofs[cind])) { 6615 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6616 cind++; 6617 } 6618 } 6619 } 6620 } 6621 } 6622 PetscFunctionReturn(PETSC_SUCCESS); 6623 } 6624 6625 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[]) 6626 { 6627 PetscScalar *a; 6628 PetscInt fdof, foff, fcdof, foffset = *offset; 6629 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6630 PetscInt cind = 0, b; 6631 6632 PetscFunctionBegin; 6633 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6634 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6635 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6636 a = &array[foff]; 6637 if (!fcdof || setBC) { 6638 if (clperm) { 6639 if (perm) { 6640 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6641 } else { 6642 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6643 } 6644 } else { 6645 if (perm) { 6646 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6647 } else { 6648 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6649 } 6650 } 6651 } else { 6652 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6653 if (clperm) { 6654 if (perm) { 6655 for (b = 0; b < fdof; b++) { 6656 if ((cind < fcdof) && (b == fcdofs[cind])) { 6657 ++cind; 6658 continue; 6659 } 6660 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6661 } 6662 } else { 6663 for (b = 0; b < fdof; b++) { 6664 if ((cind < fcdof) && (b == fcdofs[cind])) { 6665 ++cind; 6666 continue; 6667 } 6668 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6669 } 6670 } 6671 } else { 6672 if (perm) { 6673 for (b = 0; b < fdof; b++) { 6674 if ((cind < fcdof) && (b == fcdofs[cind])) { 6675 ++cind; 6676 continue; 6677 } 6678 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6679 } 6680 } else { 6681 for (b = 0; b < fdof; b++) { 6682 if ((cind < fcdof) && (b == fcdofs[cind])) { 6683 ++cind; 6684 continue; 6685 } 6686 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6687 } 6688 } 6689 } 6690 } 6691 *offset += fdof; 6692 PetscFunctionReturn(PETSC_SUCCESS); 6693 } 6694 6695 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[]) 6696 { 6697 PetscScalar *a; 6698 PetscInt fdof, foff, fcdof, foffset = *offset; 6699 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6700 PetscInt Nc, cind = 0, ncind = 0, b; 6701 PetscBool ncSet, fcSet; 6702 6703 PetscFunctionBegin; 6704 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6705 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6706 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6707 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6708 a = &array[foff]; 6709 if (fcdof) { 6710 /* We just override fcdof and fcdofs with Ncc and comps */ 6711 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6712 if (clperm) { 6713 if (perm) { 6714 if (comps) { 6715 for (b = 0; b < fdof; b++) { 6716 ncSet = fcSet = PETSC_FALSE; 6717 if (b % Nc == comps[ncind]) { 6718 ncind = (ncind + 1) % Ncc; 6719 ncSet = PETSC_TRUE; 6720 } 6721 if ((cind < fcdof) && (b == fcdofs[cind])) { 6722 ++cind; 6723 fcSet = PETSC_TRUE; 6724 } 6725 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6726 } 6727 } else { 6728 for (b = 0; b < fdof; b++) { 6729 if ((cind < fcdof) && (b == fcdofs[cind])) { 6730 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6731 ++cind; 6732 } 6733 } 6734 } 6735 } else { 6736 if (comps) { 6737 for (b = 0; b < fdof; b++) { 6738 ncSet = fcSet = PETSC_FALSE; 6739 if (b % Nc == comps[ncind]) { 6740 ncind = (ncind + 1) % Ncc; 6741 ncSet = PETSC_TRUE; 6742 } 6743 if ((cind < fcdof) && (b == fcdofs[cind])) { 6744 ++cind; 6745 fcSet = PETSC_TRUE; 6746 } 6747 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6748 } 6749 } else { 6750 for (b = 0; b < fdof; b++) { 6751 if ((cind < fcdof) && (b == fcdofs[cind])) { 6752 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6753 ++cind; 6754 } 6755 } 6756 } 6757 } 6758 } else { 6759 if (perm) { 6760 if (comps) { 6761 for (b = 0; b < fdof; b++) { 6762 ncSet = fcSet = PETSC_FALSE; 6763 if (b % Nc == comps[ncind]) { 6764 ncind = (ncind + 1) % Ncc; 6765 ncSet = PETSC_TRUE; 6766 } 6767 if ((cind < fcdof) && (b == fcdofs[cind])) { 6768 ++cind; 6769 fcSet = PETSC_TRUE; 6770 } 6771 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6772 } 6773 } else { 6774 for (b = 0; b < fdof; b++) { 6775 if ((cind < fcdof) && (b == fcdofs[cind])) { 6776 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6777 ++cind; 6778 } 6779 } 6780 } 6781 } else { 6782 if (comps) { 6783 for (b = 0; b < fdof; b++) { 6784 ncSet = fcSet = PETSC_FALSE; 6785 if (b % Nc == comps[ncind]) { 6786 ncind = (ncind + 1) % Ncc; 6787 ncSet = PETSC_TRUE; 6788 } 6789 if ((cind < fcdof) && (b == fcdofs[cind])) { 6790 ++cind; 6791 fcSet = PETSC_TRUE; 6792 } 6793 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6794 } 6795 } else { 6796 for (b = 0; b < fdof; b++) { 6797 if ((cind < fcdof) && (b == fcdofs[cind])) { 6798 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6799 ++cind; 6800 } 6801 } 6802 } 6803 } 6804 } 6805 } 6806 *offset += fdof; 6807 PetscFunctionReturn(PETSC_SUCCESS); 6808 } 6809 6810 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6811 { 6812 PetscScalar *array; 6813 const PetscInt *cone, *coneO; 6814 PetscInt pStart, pEnd, p, numPoints, off, dof; 6815 6816 PetscFunctionBeginHot; 6817 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6818 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6819 PetscCall(DMPlexGetCone(dm, point, &cone)); 6820 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6821 PetscCall(VecGetArray(v, &array)); 6822 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6823 const PetscInt cp = !p ? point : cone[p - 1]; 6824 const PetscInt o = !p ? 0 : coneO[p - 1]; 6825 6826 if ((cp < pStart) || (cp >= pEnd)) { 6827 dof = 0; 6828 continue; 6829 } 6830 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6831 /* ADD_VALUES */ 6832 { 6833 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6834 PetscScalar *a; 6835 PetscInt cdof, coff, cind = 0, k; 6836 6837 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6838 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6839 a = &array[coff]; 6840 if (!cdof) { 6841 if (o >= 0) { 6842 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6843 } else { 6844 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6845 } 6846 } else { 6847 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6848 if (o >= 0) { 6849 for (k = 0; k < dof; ++k) { 6850 if ((cind < cdof) && (k == cdofs[cind])) { 6851 ++cind; 6852 continue; 6853 } 6854 a[k] += values[off + k]; 6855 } 6856 } else { 6857 for (k = 0; k < dof; ++k) { 6858 if ((cind < cdof) && (k == cdofs[cind])) { 6859 ++cind; 6860 continue; 6861 } 6862 a[k] += values[off + dof - k - 1]; 6863 } 6864 } 6865 } 6866 } 6867 } 6868 PetscCall(VecRestoreArray(v, &array)); 6869 PetscFunctionReturn(PETSC_SUCCESS); 6870 } 6871 6872 /*@C 6873 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6874 6875 Not collective 6876 6877 Input Parameters: 6878 + dm - The `DM` 6879 . section - The section describing the layout in `v`, or `NULL` to use the default section 6880 . v - The local vector 6881 . point - The point in the `DM` 6882 . values - The array of values 6883 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6884 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6885 6886 Level: intermediate 6887 6888 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6889 @*/ 6890 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6891 { 6892 PetscSection clSection; 6893 IS clPoints; 6894 PetscScalar *array; 6895 PetscInt *points = NULL; 6896 const PetscInt *clp, *clperm = NULL; 6897 PetscInt depth, numFields, numPoints, p, clsize; 6898 6899 PetscFunctionBeginHot; 6900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6901 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6902 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6903 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6904 PetscCall(DMPlexGetDepth(dm, &depth)); 6905 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6906 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6907 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6908 PetscFunctionReturn(PETSC_SUCCESS); 6909 } 6910 /* Get points */ 6911 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6912 for (clsize = 0, p = 0; p < numPoints; p++) { 6913 PetscInt dof; 6914 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6915 clsize += dof; 6916 } 6917 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6918 /* Get array */ 6919 PetscCall(VecGetArray(v, &array)); 6920 /* Get values */ 6921 if (numFields > 0) { 6922 PetscInt offset = 0, f; 6923 for (f = 0; f < numFields; ++f) { 6924 const PetscInt **perms = NULL; 6925 const PetscScalar **flips = NULL; 6926 6927 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6928 switch (mode) { 6929 case INSERT_VALUES: 6930 for (p = 0; p < numPoints; p++) { 6931 const PetscInt point = points[2 * p]; 6932 const PetscInt *perm = perms ? perms[p] : NULL; 6933 const PetscScalar *flip = flips ? flips[p] : NULL; 6934 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6935 } 6936 break; 6937 case INSERT_ALL_VALUES: 6938 for (p = 0; p < numPoints; p++) { 6939 const PetscInt point = points[2 * p]; 6940 const PetscInt *perm = perms ? perms[p] : NULL; 6941 const PetscScalar *flip = flips ? flips[p] : NULL; 6942 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6943 } 6944 break; 6945 case INSERT_BC_VALUES: 6946 for (p = 0; p < numPoints; p++) { 6947 const PetscInt point = points[2 * p]; 6948 const PetscInt *perm = perms ? perms[p] : NULL; 6949 const PetscScalar *flip = flips ? flips[p] : NULL; 6950 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6951 } 6952 break; 6953 case ADD_VALUES: 6954 for (p = 0; p < numPoints; p++) { 6955 const PetscInt point = points[2 * p]; 6956 const PetscInt *perm = perms ? perms[p] : NULL; 6957 const PetscScalar *flip = flips ? flips[p] : NULL; 6958 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6959 } 6960 break; 6961 case ADD_ALL_VALUES: 6962 for (p = 0; p < numPoints; p++) { 6963 const PetscInt point = points[2 * p]; 6964 const PetscInt *perm = perms ? perms[p] : NULL; 6965 const PetscScalar *flip = flips ? flips[p] : NULL; 6966 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6967 } 6968 break; 6969 case ADD_BC_VALUES: 6970 for (p = 0; p < numPoints; p++) { 6971 const PetscInt point = points[2 * p]; 6972 const PetscInt *perm = perms ? perms[p] : NULL; 6973 const PetscScalar *flip = flips ? flips[p] : NULL; 6974 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6975 } 6976 break; 6977 default: 6978 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6979 } 6980 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6981 } 6982 } else { 6983 PetscInt dof, off; 6984 const PetscInt **perms = NULL; 6985 const PetscScalar **flips = NULL; 6986 6987 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6988 switch (mode) { 6989 case INSERT_VALUES: 6990 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6991 const PetscInt point = points[2 * p]; 6992 const PetscInt *perm = perms ? perms[p] : NULL; 6993 const PetscScalar *flip = flips ? flips[p] : NULL; 6994 PetscCall(PetscSectionGetDof(section, point, &dof)); 6995 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6996 } 6997 break; 6998 case INSERT_ALL_VALUES: 6999 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7000 const PetscInt point = points[2 * p]; 7001 const PetscInt *perm = perms ? perms[p] : NULL; 7002 const PetscScalar *flip = flips ? flips[p] : NULL; 7003 PetscCall(PetscSectionGetDof(section, point, &dof)); 7004 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7005 } 7006 break; 7007 case INSERT_BC_VALUES: 7008 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7009 const PetscInt point = points[2 * p]; 7010 const PetscInt *perm = perms ? perms[p] : NULL; 7011 const PetscScalar *flip = flips ? flips[p] : NULL; 7012 PetscCall(PetscSectionGetDof(section, point, &dof)); 7013 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7014 } 7015 break; 7016 case ADD_VALUES: 7017 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 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(PetscSectionGetDof(section, point, &dof)); 7022 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7023 } 7024 break; 7025 case ADD_ALL_VALUES: 7026 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7027 const PetscInt point = points[2 * p]; 7028 const PetscInt *perm = perms ? perms[p] : NULL; 7029 const PetscScalar *flip = flips ? flips[p] : NULL; 7030 PetscCall(PetscSectionGetDof(section, point, &dof)); 7031 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7032 } 7033 break; 7034 case ADD_BC_VALUES: 7035 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7036 const PetscInt point = points[2 * p]; 7037 const PetscInt *perm = perms ? perms[p] : NULL; 7038 const PetscScalar *flip = flips ? flips[p] : NULL; 7039 PetscCall(PetscSectionGetDof(section, point, &dof)); 7040 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7041 } 7042 break; 7043 default: 7044 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7045 } 7046 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7047 } 7048 /* Cleanup points */ 7049 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7050 /* Cleanup array */ 7051 PetscCall(VecRestoreArray(v, &array)); 7052 PetscFunctionReturn(PETSC_SUCCESS); 7053 } 7054 7055 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7056 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7057 { 7058 PetscFunctionBegin; 7059 *contains = PETSC_TRUE; 7060 if (label) { 7061 PetscInt fdof; 7062 7063 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7064 if (!*contains) { 7065 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7066 *offset += fdof; 7067 PetscFunctionReturn(PETSC_SUCCESS); 7068 } 7069 } 7070 PetscFunctionReturn(PETSC_SUCCESS); 7071 } 7072 7073 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7074 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) 7075 { 7076 PetscSection clSection; 7077 IS clPoints; 7078 PetscScalar *array; 7079 PetscInt *points = NULL; 7080 const PetscInt *clp; 7081 PetscInt numFields, numPoints, p; 7082 PetscInt offset = 0, f; 7083 7084 PetscFunctionBeginHot; 7085 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7086 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7087 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7088 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7089 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7090 /* Get points */ 7091 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7092 /* Get array */ 7093 PetscCall(VecGetArray(v, &array)); 7094 /* Get values */ 7095 for (f = 0; f < numFields; ++f) { 7096 const PetscInt **perms = NULL; 7097 const PetscScalar **flips = NULL; 7098 PetscBool contains; 7099 7100 if (!fieldActive[f]) { 7101 for (p = 0; p < numPoints * 2; p += 2) { 7102 PetscInt fdof; 7103 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7104 offset += fdof; 7105 } 7106 continue; 7107 } 7108 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7109 switch (mode) { 7110 case INSERT_VALUES: 7111 for (p = 0; p < numPoints; p++) { 7112 const PetscInt point = points[2 * p]; 7113 const PetscInt *perm = perms ? perms[p] : NULL; 7114 const PetscScalar *flip = flips ? flips[p] : NULL; 7115 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7116 if (!contains) continue; 7117 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7118 } 7119 break; 7120 case INSERT_ALL_VALUES: 7121 for (p = 0; p < numPoints; p++) { 7122 const PetscInt point = points[2 * p]; 7123 const PetscInt *perm = perms ? perms[p] : NULL; 7124 const PetscScalar *flip = flips ? flips[p] : NULL; 7125 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7126 if (!contains) continue; 7127 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7128 } 7129 break; 7130 case INSERT_BC_VALUES: 7131 for (p = 0; p < numPoints; p++) { 7132 const PetscInt point = points[2 * p]; 7133 const PetscInt *perm = perms ? perms[p] : NULL; 7134 const PetscScalar *flip = flips ? flips[p] : NULL; 7135 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7136 if (!contains) continue; 7137 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7138 } 7139 break; 7140 case ADD_VALUES: 7141 for (p = 0; p < numPoints; p++) { 7142 const PetscInt point = points[2 * p]; 7143 const PetscInt *perm = perms ? perms[p] : NULL; 7144 const PetscScalar *flip = flips ? flips[p] : NULL; 7145 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7146 if (!contains) continue; 7147 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7148 } 7149 break; 7150 case ADD_ALL_VALUES: 7151 for (p = 0; p < numPoints; p++) { 7152 const PetscInt point = points[2 * p]; 7153 const PetscInt *perm = perms ? perms[p] : NULL; 7154 const PetscScalar *flip = flips ? flips[p] : NULL; 7155 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7156 if (!contains) continue; 7157 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7158 } 7159 break; 7160 default: 7161 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7162 } 7163 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7164 } 7165 /* Cleanup points */ 7166 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7167 /* Cleanup array */ 7168 PetscCall(VecRestoreArray(v, &array)); 7169 PetscFunctionReturn(PETSC_SUCCESS); 7170 } 7171 7172 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7173 { 7174 PetscMPIInt rank; 7175 PetscInt i, j; 7176 7177 PetscFunctionBegin; 7178 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7179 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7180 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7181 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7182 numCIndices = numCIndices ? numCIndices : numRIndices; 7183 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7184 for (i = 0; i < numRIndices; i++) { 7185 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7186 for (j = 0; j < numCIndices; j++) { 7187 #if defined(PETSC_USE_COMPLEX) 7188 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7189 #else 7190 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7191 #endif 7192 } 7193 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7194 } 7195 PetscFunctionReturn(PETSC_SUCCESS); 7196 } 7197 7198 /* 7199 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7200 7201 Input Parameters: 7202 + section - The section for this data layout 7203 . islocal - Is the section (and thus indices being requested) local or global? 7204 . point - The point contributing dofs with these indices 7205 . off - The global offset of this point 7206 . loff - The local offset of each field 7207 . setBC - The flag determining whether to include indices of boundary values 7208 . perm - A permutation of the dofs on this point, or NULL 7209 - indperm - A permutation of the entire indices array, or NULL 7210 7211 Output Parameter: 7212 . indices - Indices for dofs on this point 7213 7214 Level: developer 7215 7216 Note: The indices could be local or global, depending on the value of 'off'. 7217 */ 7218 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7219 { 7220 PetscInt dof; /* The number of unknowns on this point */ 7221 PetscInt cdof; /* The number of constraints on this point */ 7222 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7223 PetscInt cind = 0, k; 7224 7225 PetscFunctionBegin; 7226 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7227 PetscCall(PetscSectionGetDof(section, point, &dof)); 7228 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7229 if (!cdof || setBC) { 7230 for (k = 0; k < dof; ++k) { 7231 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7232 const PetscInt ind = indperm ? indperm[preind] : preind; 7233 7234 indices[ind] = off + k; 7235 } 7236 } else { 7237 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7238 for (k = 0; k < dof; ++k) { 7239 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7240 const PetscInt ind = indperm ? indperm[preind] : preind; 7241 7242 if ((cind < cdof) && (k == cdofs[cind])) { 7243 /* Insert check for returning constrained indices */ 7244 indices[ind] = -(off + k + 1); 7245 ++cind; 7246 } else { 7247 indices[ind] = off + k - (islocal ? 0 : cind); 7248 } 7249 } 7250 } 7251 *loff += dof; 7252 PetscFunctionReturn(PETSC_SUCCESS); 7253 } 7254 7255 /* 7256 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7257 7258 Input Parameters: 7259 + section - a section (global or local) 7260 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7261 . point - point within section 7262 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7263 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7264 . setBC - identify constrained (boundary condition) points via involution. 7265 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7266 . permsoff - offset 7267 - indperm - index permutation 7268 7269 Output Parameter: 7270 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7271 . indices - array to hold indices (as defined by section) of each dof associated with point 7272 7273 Notes: 7274 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7275 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7276 in the local vector. 7277 7278 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7279 significant). It is invalid to call with a global section and setBC=true. 7280 7281 Developer Note: 7282 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7283 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7284 offset could be obtained from the section instead of passing it explicitly as we do now. 7285 7286 Example: 7287 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7288 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7289 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7290 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. 7291 7292 Level: developer 7293 */ 7294 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[]) 7295 { 7296 PetscInt numFields, foff, f; 7297 7298 PetscFunctionBegin; 7299 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7300 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7301 for (f = 0, foff = 0; f < numFields; ++f) { 7302 PetscInt fdof, cfdof; 7303 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7304 PetscInt cind = 0, b; 7305 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7306 7307 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7308 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7309 if (!cfdof || setBC) { 7310 for (b = 0; b < fdof; ++b) { 7311 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7312 const PetscInt ind = indperm ? indperm[preind] : preind; 7313 7314 indices[ind] = off + foff + b; 7315 } 7316 } else { 7317 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7318 for (b = 0; b < fdof; ++b) { 7319 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7320 const PetscInt ind = indperm ? indperm[preind] : preind; 7321 7322 if ((cind < cfdof) && (b == fcdofs[cind])) { 7323 indices[ind] = -(off + foff + b + 1); 7324 ++cind; 7325 } else { 7326 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7327 } 7328 } 7329 } 7330 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7331 foffs[f] += fdof; 7332 } 7333 PetscFunctionReturn(PETSC_SUCCESS); 7334 } 7335 7336 /* 7337 This version believes the globalSection offsets for each field, rather than just the point offset 7338 7339 . foffs - The offset into 'indices' for each field, since it is segregated by field 7340 7341 Notes: 7342 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7343 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7344 */ 7345 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7346 { 7347 PetscInt numFields, foff, f; 7348 7349 PetscFunctionBegin; 7350 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7351 for (f = 0; f < numFields; ++f) { 7352 PetscInt fdof, cfdof; 7353 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7354 PetscInt cind = 0, b; 7355 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7356 7357 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7358 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7359 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7360 if (!cfdof) { 7361 for (b = 0; b < fdof; ++b) { 7362 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7363 const PetscInt ind = indperm ? indperm[preind] : preind; 7364 7365 indices[ind] = foff + b; 7366 } 7367 } else { 7368 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7369 for (b = 0; b < fdof; ++b) { 7370 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7371 const PetscInt ind = indperm ? indperm[preind] : preind; 7372 7373 if ((cind < cfdof) && (b == fcdofs[cind])) { 7374 indices[ind] = -(foff + b + 1); 7375 ++cind; 7376 } else { 7377 indices[ind] = foff + b - cind; 7378 } 7379 } 7380 } 7381 foffs[f] += fdof; 7382 } 7383 PetscFunctionReturn(PETSC_SUCCESS); 7384 } 7385 7386 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) 7387 { 7388 Mat cMat; 7389 PetscSection aSec, cSec; 7390 IS aIS; 7391 PetscInt aStart = -1, aEnd = -1; 7392 const PetscInt *anchors; 7393 PetscInt numFields, f, p, q, newP = 0; 7394 PetscInt newNumPoints = 0, newNumIndices = 0; 7395 PetscInt *newPoints, *indices, *newIndices; 7396 PetscInt maxAnchor, maxDof; 7397 PetscInt newOffsets[32]; 7398 PetscInt *pointMatOffsets[32]; 7399 PetscInt *newPointOffsets[32]; 7400 PetscScalar *pointMat[32]; 7401 PetscScalar *newValues = NULL, *tmpValues; 7402 PetscBool anyConstrained = PETSC_FALSE; 7403 7404 PetscFunctionBegin; 7405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7406 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7407 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7408 7409 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7410 /* if there are point-to-point constraints */ 7411 if (aSec) { 7412 PetscCall(PetscArrayzero(newOffsets, 32)); 7413 PetscCall(ISGetIndices(aIS, &anchors)); 7414 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7415 /* figure out how many points are going to be in the new element matrix 7416 * (we allow double counting, because it's all just going to be summed 7417 * into the global matrix anyway) */ 7418 for (p = 0; p < 2 * numPoints; p += 2) { 7419 PetscInt b = points[p]; 7420 PetscInt bDof = 0, bSecDof; 7421 7422 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7423 if (!bSecDof) continue; 7424 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7425 if (bDof) { 7426 /* this point is constrained */ 7427 /* it is going to be replaced by its anchors */ 7428 PetscInt bOff, q; 7429 7430 anyConstrained = PETSC_TRUE; 7431 newNumPoints += bDof; 7432 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7433 for (q = 0; q < bDof; q++) { 7434 PetscInt a = anchors[bOff + q]; 7435 PetscInt aDof; 7436 7437 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7438 newNumIndices += aDof; 7439 for (f = 0; f < numFields; ++f) { 7440 PetscInt fDof; 7441 7442 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7443 newOffsets[f + 1] += fDof; 7444 } 7445 } 7446 } else { 7447 /* this point is not constrained */ 7448 newNumPoints++; 7449 newNumIndices += bSecDof; 7450 for (f = 0; f < numFields; ++f) { 7451 PetscInt fDof; 7452 7453 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7454 newOffsets[f + 1] += fDof; 7455 } 7456 } 7457 } 7458 } 7459 if (!anyConstrained) { 7460 if (outNumPoints) *outNumPoints = 0; 7461 if (outNumIndices) *outNumIndices = 0; 7462 if (outPoints) *outPoints = NULL; 7463 if (outValues) *outValues = NULL; 7464 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7465 PetscFunctionReturn(PETSC_SUCCESS); 7466 } 7467 7468 if (outNumPoints) *outNumPoints = newNumPoints; 7469 if (outNumIndices) *outNumIndices = newNumIndices; 7470 7471 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7472 7473 if (!outPoints && !outValues) { 7474 if (offsets) { 7475 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7476 } 7477 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7478 PetscFunctionReturn(PETSC_SUCCESS); 7479 } 7480 7481 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7482 7483 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7484 7485 /* workspaces */ 7486 if (numFields) { 7487 for (f = 0; f < numFields; f++) { 7488 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7489 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7490 } 7491 } else { 7492 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7493 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7494 } 7495 7496 /* get workspaces for the point-to-point matrices */ 7497 if (numFields) { 7498 PetscInt totalOffset, totalMatOffset; 7499 7500 for (p = 0; p < numPoints; p++) { 7501 PetscInt b = points[2 * p]; 7502 PetscInt bDof = 0, bSecDof; 7503 7504 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7505 if (!bSecDof) { 7506 for (f = 0; f < numFields; f++) { 7507 newPointOffsets[f][p + 1] = 0; 7508 pointMatOffsets[f][p + 1] = 0; 7509 } 7510 continue; 7511 } 7512 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7513 if (bDof) { 7514 for (f = 0; f < numFields; f++) { 7515 PetscInt fDof, q, bOff, allFDof = 0; 7516 7517 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7518 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7519 for (q = 0; q < bDof; q++) { 7520 PetscInt a = anchors[bOff + q]; 7521 PetscInt aFDof; 7522 7523 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7524 allFDof += aFDof; 7525 } 7526 newPointOffsets[f][p + 1] = allFDof; 7527 pointMatOffsets[f][p + 1] = fDof * allFDof; 7528 } 7529 } else { 7530 for (f = 0; f < numFields; f++) { 7531 PetscInt fDof; 7532 7533 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7534 newPointOffsets[f][p + 1] = fDof; 7535 pointMatOffsets[f][p + 1] = 0; 7536 } 7537 } 7538 } 7539 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7540 newPointOffsets[f][0] = totalOffset; 7541 pointMatOffsets[f][0] = totalMatOffset; 7542 for (p = 0; p < numPoints; p++) { 7543 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7544 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7545 } 7546 totalOffset = newPointOffsets[f][numPoints]; 7547 totalMatOffset = pointMatOffsets[f][numPoints]; 7548 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7549 } 7550 } else { 7551 for (p = 0; p < numPoints; p++) { 7552 PetscInt b = points[2 * p]; 7553 PetscInt bDof = 0, bSecDof; 7554 7555 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7556 if (!bSecDof) { 7557 newPointOffsets[0][p + 1] = 0; 7558 pointMatOffsets[0][p + 1] = 0; 7559 continue; 7560 } 7561 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7562 if (bDof) { 7563 PetscInt bOff, q, allDof = 0; 7564 7565 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7566 for (q = 0; q < bDof; q++) { 7567 PetscInt a = anchors[bOff + q], aDof; 7568 7569 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7570 allDof += aDof; 7571 } 7572 newPointOffsets[0][p + 1] = allDof; 7573 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7574 } else { 7575 newPointOffsets[0][p + 1] = bSecDof; 7576 pointMatOffsets[0][p + 1] = 0; 7577 } 7578 } 7579 newPointOffsets[0][0] = 0; 7580 pointMatOffsets[0][0] = 0; 7581 for (p = 0; p < numPoints; p++) { 7582 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7583 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7584 } 7585 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7586 } 7587 7588 /* output arrays */ 7589 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7590 7591 /* get the point-to-point matrices; construct newPoints */ 7592 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7593 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7594 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7595 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7596 if (numFields) { 7597 for (p = 0, newP = 0; p < numPoints; p++) { 7598 PetscInt b = points[2 * p]; 7599 PetscInt o = points[2 * p + 1]; 7600 PetscInt bDof = 0, bSecDof; 7601 7602 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7603 if (!bSecDof) continue; 7604 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7605 if (bDof) { 7606 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7607 7608 fStart[0] = 0; 7609 fEnd[0] = 0; 7610 for (f = 0; f < numFields; f++) { 7611 PetscInt fDof; 7612 7613 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7614 fStart[f + 1] = fStart[f] + fDof; 7615 fEnd[f + 1] = fStart[f + 1]; 7616 } 7617 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7618 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7619 7620 fAnchorStart[0] = 0; 7621 fAnchorEnd[0] = 0; 7622 for (f = 0; f < numFields; f++) { 7623 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7624 7625 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7626 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7627 } 7628 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7629 for (q = 0; q < bDof; q++) { 7630 PetscInt a = anchors[bOff + q], aOff; 7631 7632 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7633 newPoints[2 * (newP + q)] = a; 7634 newPoints[2 * (newP + q) + 1] = 0; 7635 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7636 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7637 } 7638 newP += bDof; 7639 7640 if (outValues) { 7641 /* get the point-to-point submatrix */ 7642 for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p])); 7643 } 7644 } else { 7645 newPoints[2 * newP] = b; 7646 newPoints[2 * newP + 1] = o; 7647 newP++; 7648 } 7649 } 7650 } else { 7651 for (p = 0; p < numPoints; p++) { 7652 PetscInt b = points[2 * p]; 7653 PetscInt o = points[2 * p + 1]; 7654 PetscInt bDof = 0, bSecDof; 7655 7656 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7657 if (!bSecDof) continue; 7658 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7659 if (bDof) { 7660 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7661 7662 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7663 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7664 7665 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7666 for (q = 0; q < bDof; q++) { 7667 PetscInt a = anchors[bOff + q], aOff; 7668 7669 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7670 7671 newPoints[2 * (newP + q)] = a; 7672 newPoints[2 * (newP + q) + 1] = 0; 7673 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7674 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7675 } 7676 newP += bDof; 7677 7678 /* get the point-to-point submatrix */ 7679 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7680 } else { 7681 newPoints[2 * newP] = b; 7682 newPoints[2 * newP + 1] = o; 7683 newP++; 7684 } 7685 } 7686 } 7687 7688 if (outValues) { 7689 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7690 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7691 /* multiply constraints on the right */ 7692 if (numFields) { 7693 for (f = 0; f < numFields; f++) { 7694 PetscInt oldOff = offsets[f]; 7695 7696 for (p = 0; p < numPoints; p++) { 7697 PetscInt cStart = newPointOffsets[f][p]; 7698 PetscInt b = points[2 * p]; 7699 PetscInt c, r, k; 7700 PetscInt dof; 7701 7702 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7703 if (!dof) continue; 7704 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7705 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7706 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7707 7708 for (r = 0; r < numIndices; r++) { 7709 for (c = 0; c < nCols; c++) { 7710 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7711 } 7712 } 7713 } else { 7714 /* copy this column as is */ 7715 for (r = 0; r < numIndices; r++) { 7716 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7717 } 7718 } 7719 oldOff += dof; 7720 } 7721 } 7722 } else { 7723 PetscInt oldOff = 0; 7724 for (p = 0; p < numPoints; p++) { 7725 PetscInt cStart = newPointOffsets[0][p]; 7726 PetscInt b = points[2 * p]; 7727 PetscInt c, r, k; 7728 PetscInt dof; 7729 7730 PetscCall(PetscSectionGetDof(section, b, &dof)); 7731 if (!dof) continue; 7732 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7733 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7734 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7735 7736 for (r = 0; r < numIndices; r++) { 7737 for (c = 0; c < nCols; c++) { 7738 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7739 } 7740 } 7741 } else { 7742 /* copy this column as is */ 7743 for (r = 0; r < numIndices; r++) { 7744 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7745 } 7746 } 7747 oldOff += dof; 7748 } 7749 } 7750 7751 if (multiplyLeft) { 7752 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7753 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7754 /* multiply constraints transpose on the left */ 7755 if (numFields) { 7756 for (f = 0; f < numFields; f++) { 7757 PetscInt oldOff = offsets[f]; 7758 7759 for (p = 0; p < numPoints; p++) { 7760 PetscInt rStart = newPointOffsets[f][p]; 7761 PetscInt b = points[2 * p]; 7762 PetscInt c, r, k; 7763 PetscInt dof; 7764 7765 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7766 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7767 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7768 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7769 7770 for (r = 0; r < nRows; r++) { 7771 for (c = 0; c < newNumIndices; c++) { 7772 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7773 } 7774 } 7775 } else { 7776 /* copy this row as is */ 7777 for (r = 0; r < dof; r++) { 7778 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7779 } 7780 } 7781 oldOff += dof; 7782 } 7783 } 7784 } else { 7785 PetscInt oldOff = 0; 7786 7787 for (p = 0; p < numPoints; p++) { 7788 PetscInt rStart = newPointOffsets[0][p]; 7789 PetscInt b = points[2 * p]; 7790 PetscInt c, r, k; 7791 PetscInt dof; 7792 7793 PetscCall(PetscSectionGetDof(section, b, &dof)); 7794 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7795 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7796 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7797 7798 for (r = 0; r < nRows; r++) { 7799 for (c = 0; c < newNumIndices; c++) { 7800 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7801 } 7802 } 7803 } else { 7804 /* copy this row as is */ 7805 for (r = 0; r < dof; r++) { 7806 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7807 } 7808 } 7809 oldOff += dof; 7810 } 7811 } 7812 7813 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7814 } else { 7815 newValues = tmpValues; 7816 } 7817 } 7818 7819 /* clean up */ 7820 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7821 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7822 7823 if (numFields) { 7824 for (f = 0; f < numFields; f++) { 7825 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7826 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7827 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7828 } 7829 } else { 7830 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7831 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7832 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7833 } 7834 PetscCall(ISRestoreIndices(aIS, &anchors)); 7835 7836 /* output */ 7837 if (outPoints) { 7838 *outPoints = newPoints; 7839 } else { 7840 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7841 } 7842 if (outValues) *outValues = newValues; 7843 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7844 PetscFunctionReturn(PETSC_SUCCESS); 7845 } 7846 7847 /*@C 7848 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7849 7850 Not collective 7851 7852 Input Parameters: 7853 + dm - The `DM` 7854 . section - The `PetscSection` describing the points (a local section) 7855 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7856 . point - The point defining the closure 7857 - useClPerm - Use the closure point permutation if available 7858 7859 Output Parameters: 7860 + numIndices - The number of dof indices in the closure of point with the input sections 7861 . indices - The dof indices 7862 . outOffsets - Array to write the field offsets into, or `NULL` 7863 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7864 7865 Level: advanced 7866 7867 Notes: 7868 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7869 7870 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7871 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7872 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7873 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7874 indices (with the above semantics) are implied. 7875 7876 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7877 `PetscSection`, `DMGetGlobalSection()` 7878 @*/ 7879 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7880 { 7881 /* Closure ordering */ 7882 PetscSection clSection; 7883 IS clPoints; 7884 const PetscInt *clp; 7885 PetscInt *points; 7886 const PetscInt *clperm = NULL; 7887 /* Dof permutation and sign flips */ 7888 const PetscInt **perms[32] = {NULL}; 7889 const PetscScalar **flips[32] = {NULL}; 7890 PetscScalar *valCopy = NULL; 7891 /* Hanging node constraints */ 7892 PetscInt *pointsC = NULL; 7893 PetscScalar *valuesC = NULL; 7894 PetscInt NclC, NiC; 7895 7896 PetscInt *idx; 7897 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7898 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7899 7900 PetscFunctionBeginHot; 7901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7902 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7903 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7904 if (numIndices) PetscAssertPointer(numIndices, 6); 7905 if (indices) PetscAssertPointer(indices, 7); 7906 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7907 if (values) PetscAssertPointer(values, 9); 7908 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7909 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7910 PetscCall(PetscArrayzero(offsets, 32)); 7911 /* 1) Get points in closure */ 7912 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7913 if (useClPerm) { 7914 PetscInt depth, clsize; 7915 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7916 for (clsize = 0, p = 0; p < Ncl; p++) { 7917 PetscInt dof; 7918 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7919 clsize += dof; 7920 } 7921 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7922 } 7923 /* 2) Get number of indices on these points and field offsets from section */ 7924 for (p = 0; p < Ncl * 2; p += 2) { 7925 PetscInt dof, fdof; 7926 7927 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7928 for (f = 0; f < Nf; ++f) { 7929 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7930 offsets[f + 1] += fdof; 7931 } 7932 Ni += dof; 7933 } 7934 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7935 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7936 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7937 for (f = 0; f < PetscMax(1, Nf); ++f) { 7938 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7939 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7940 /* may need to apply sign changes to the element matrix */ 7941 if (values && flips[f]) { 7942 PetscInt foffset = offsets[f]; 7943 7944 for (p = 0; p < Ncl; ++p) { 7945 PetscInt pnt = points[2 * p], fdof; 7946 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7947 7948 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7949 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7950 if (flip) { 7951 PetscInt i, j, k; 7952 7953 if (!valCopy) { 7954 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7955 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7956 *values = valCopy; 7957 } 7958 for (i = 0; i < fdof; ++i) { 7959 PetscScalar fval = flip[i]; 7960 7961 for (k = 0; k < Ni; ++k) { 7962 valCopy[Ni * (foffset + i) + k] *= fval; 7963 valCopy[Ni * k + (foffset + i)] *= fval; 7964 } 7965 } 7966 } 7967 foffset += fdof; 7968 } 7969 } 7970 } 7971 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7972 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7973 if (NclC) { 7974 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7975 for (f = 0; f < PetscMax(1, Nf); ++f) { 7976 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7977 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7978 } 7979 for (f = 0; f < PetscMax(1, Nf); ++f) { 7980 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7981 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7982 } 7983 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7984 Ncl = NclC; 7985 Ni = NiC; 7986 points = pointsC; 7987 if (values) *values = valuesC; 7988 } 7989 /* 5) Calculate indices */ 7990 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7991 if (Nf) { 7992 PetscInt idxOff; 7993 PetscBool useFieldOffsets; 7994 7995 if (outOffsets) { 7996 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7997 } 7998 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7999 if (useFieldOffsets) { 8000 for (p = 0; p < Ncl; ++p) { 8001 const PetscInt pnt = points[p * 2]; 8002 8003 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8004 } 8005 } else { 8006 for (p = 0; p < Ncl; ++p) { 8007 const PetscInt pnt = points[p * 2]; 8008 8009 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8010 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8011 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8012 * global section. */ 8013 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8014 } 8015 } 8016 } else { 8017 PetscInt off = 0, idxOff; 8018 8019 for (p = 0; p < Ncl; ++p) { 8020 const PetscInt pnt = points[p * 2]; 8021 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8022 8023 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8024 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8025 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8026 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8027 } 8028 } 8029 /* 6) Cleanup */ 8030 for (f = 0; f < PetscMax(1, Nf); ++f) { 8031 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8032 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8033 } 8034 if (NclC) { 8035 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8036 } else { 8037 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8038 } 8039 8040 if (numIndices) *numIndices = Ni; 8041 if (indices) *indices = idx; 8042 PetscFunctionReturn(PETSC_SUCCESS); 8043 } 8044 8045 /*@C 8046 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8047 8048 Not collective 8049 8050 Input Parameters: 8051 + dm - The `DM` 8052 . section - The `PetscSection` describing the points (a local section) 8053 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8054 . point - The point defining the closure 8055 - useClPerm - Use the closure point permutation if available 8056 8057 Output Parameters: 8058 + numIndices - The number of dof indices in the closure of point with the input sections 8059 . indices - The dof indices 8060 . outOffsets - Array to write the field offsets into, or `NULL` 8061 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8062 8063 Level: advanced 8064 8065 Notes: 8066 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8067 8068 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8069 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8070 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8071 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8072 indices (with the above semantics) are implied. 8073 8074 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8075 @*/ 8076 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8077 { 8078 PetscFunctionBegin; 8079 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8080 PetscAssertPointer(indices, 7); 8081 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8082 PetscFunctionReturn(PETSC_SUCCESS); 8083 } 8084 8085 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8086 { 8087 DM_Plex *mesh = (DM_Plex *)dm->data; 8088 PetscInt *indices; 8089 PetscInt numIndices; 8090 const PetscScalar *valuesOrig = values; 8091 PetscErrorCode ierr; 8092 8093 PetscFunctionBegin; 8094 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8095 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8096 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8097 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8098 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8099 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8100 8101 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8102 8103 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8104 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8105 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8106 if (ierr) { 8107 PetscMPIInt rank; 8108 8109 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8110 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8111 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8112 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8113 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8114 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8115 } 8116 if (mesh->printFEM > 1) { 8117 PetscInt i; 8118 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8119 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8120 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8121 } 8122 8123 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8124 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8125 PetscFunctionReturn(PETSC_SUCCESS); 8126 } 8127 8128 /*@C 8129 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8130 8131 Not collective 8132 8133 Input Parameters: 8134 + dm - The `DM` 8135 . section - The section describing the layout in `v`, or `NULL` to use the default section 8136 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8137 . A - The matrix 8138 . point - The point in the `DM` 8139 . values - The array of values 8140 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8141 8142 Level: intermediate 8143 8144 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8145 @*/ 8146 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8147 { 8148 PetscFunctionBegin; 8149 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8150 PetscFunctionReturn(PETSC_SUCCESS); 8151 } 8152 8153 /*@C 8154 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8155 8156 Not collective 8157 8158 Input Parameters: 8159 + dmRow - The `DM` for the row fields 8160 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8161 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8162 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8163 . dmCol - The `DM` for the column fields 8164 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8165 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8166 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8167 . A - The matrix 8168 . point - The point in the `DM` 8169 . values - The array of values 8170 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8171 8172 Level: intermediate 8173 8174 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8175 @*/ 8176 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, PetscBool useRowPerm, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, PetscBool useColPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8177 { 8178 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8179 PetscInt *indicesRow, *indicesCol; 8180 PetscInt numIndicesRow, numIndicesCol; 8181 const PetscScalar *valuesOrig = values; 8182 PetscErrorCode ierr; 8183 8184 PetscFunctionBegin; 8185 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8186 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8187 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8188 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8189 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8190 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8191 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8192 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8193 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8194 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8195 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8196 8197 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8198 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8199 8200 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8201 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8202 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8203 if (ierr) { 8204 PetscMPIInt rank; 8205 8206 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8207 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8208 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8209 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8210 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8211 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8212 } 8213 8214 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8215 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8216 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8217 PetscFunctionReturn(PETSC_SUCCESS); 8218 } 8219 8220 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8221 { 8222 DM_Plex *mesh = (DM_Plex *)dmf->data; 8223 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8224 PetscInt *cpoints = NULL; 8225 PetscInt *findices, *cindices; 8226 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8227 PetscInt foffsets[32], coffsets[32]; 8228 DMPolytopeType ct; 8229 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8230 PetscErrorCode ierr; 8231 8232 PetscFunctionBegin; 8233 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8234 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8235 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8236 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8237 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8238 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8239 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8240 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8241 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8242 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8243 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8244 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8245 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8246 PetscCall(PetscArrayzero(foffsets, 32)); 8247 PetscCall(PetscArrayzero(coffsets, 32)); 8248 /* Column indices */ 8249 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8250 maxFPoints = numCPoints; 8251 /* Compress out points not in the section */ 8252 /* TODO: Squeeze out points with 0 dof as well */ 8253 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8254 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8255 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8256 cpoints[q * 2] = cpoints[p]; 8257 cpoints[q * 2 + 1] = cpoints[p + 1]; 8258 ++q; 8259 } 8260 } 8261 numCPoints = q; 8262 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8263 PetscInt fdof; 8264 8265 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8266 if (!dof) continue; 8267 for (f = 0; f < numFields; ++f) { 8268 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8269 coffsets[f + 1] += fdof; 8270 } 8271 numCIndices += dof; 8272 } 8273 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8274 /* Row indices */ 8275 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8276 { 8277 DMPlexTransform tr; 8278 DMPolytopeType *rct; 8279 PetscInt *rsize, *rcone, *rornt, Nt; 8280 8281 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8282 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8283 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8284 numSubcells = rsize[Nt - 1]; 8285 PetscCall(DMPlexTransformDestroy(&tr)); 8286 } 8287 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8288 for (r = 0, q = 0; r < numSubcells; ++r) { 8289 /* TODO Map from coarse to fine cells */ 8290 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8291 /* Compress out points not in the section */ 8292 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8293 for (p = 0; p < numFPoints * 2; p += 2) { 8294 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8295 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8296 if (!dof) continue; 8297 for (s = 0; s < q; ++s) 8298 if (fpoints[p] == ftotpoints[s * 2]) break; 8299 if (s < q) continue; 8300 ftotpoints[q * 2] = fpoints[p]; 8301 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8302 ++q; 8303 } 8304 } 8305 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8306 } 8307 numFPoints = q; 8308 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8309 PetscInt fdof; 8310 8311 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8312 if (!dof) continue; 8313 for (f = 0; f < numFields; ++f) { 8314 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8315 foffsets[f + 1] += fdof; 8316 } 8317 numFIndices += dof; 8318 } 8319 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8320 8321 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8322 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8323 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8324 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8325 if (numFields) { 8326 const PetscInt **permsF[32] = {NULL}; 8327 const PetscInt **permsC[32] = {NULL}; 8328 8329 for (f = 0; f < numFields; f++) { 8330 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8331 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8332 } 8333 for (p = 0; p < numFPoints; p++) { 8334 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8335 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8336 } 8337 for (p = 0; p < numCPoints; p++) { 8338 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8339 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8340 } 8341 for (f = 0; f < numFields; f++) { 8342 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8343 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8344 } 8345 } else { 8346 const PetscInt **permsF = NULL; 8347 const PetscInt **permsC = NULL; 8348 8349 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8350 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8351 for (p = 0, off = 0; p < numFPoints; p++) { 8352 const PetscInt *perm = permsF ? permsF[p] : NULL; 8353 8354 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8355 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8356 } 8357 for (p = 0, off = 0; p < numCPoints; p++) { 8358 const PetscInt *perm = permsC ? permsC[p] : NULL; 8359 8360 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8361 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8362 } 8363 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8364 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8365 } 8366 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8367 /* TODO: flips */ 8368 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8369 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8370 if (ierr) { 8371 PetscMPIInt rank; 8372 8373 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8374 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8375 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8376 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8377 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8378 } 8379 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8380 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8381 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8382 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8383 PetscFunctionReturn(PETSC_SUCCESS); 8384 } 8385 8386 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8387 { 8388 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8389 PetscInt *cpoints = NULL; 8390 PetscInt foffsets[32], coffsets[32]; 8391 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8392 DMPolytopeType ct; 8393 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8394 8395 PetscFunctionBegin; 8396 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8397 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8398 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8399 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8400 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8401 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8402 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8403 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8404 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8405 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8406 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8407 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8408 PetscCall(PetscArrayzero(foffsets, 32)); 8409 PetscCall(PetscArrayzero(coffsets, 32)); 8410 /* Column indices */ 8411 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8412 maxFPoints = numCPoints; 8413 /* Compress out points not in the section */ 8414 /* TODO: Squeeze out points with 0 dof as well */ 8415 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8416 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8417 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8418 cpoints[q * 2] = cpoints[p]; 8419 cpoints[q * 2 + 1] = cpoints[p + 1]; 8420 ++q; 8421 } 8422 } 8423 numCPoints = q; 8424 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8425 PetscInt fdof; 8426 8427 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8428 if (!dof) continue; 8429 for (f = 0; f < numFields; ++f) { 8430 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8431 coffsets[f + 1] += fdof; 8432 } 8433 numCIndices += dof; 8434 } 8435 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8436 /* Row indices */ 8437 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8438 { 8439 DMPlexTransform tr; 8440 DMPolytopeType *rct; 8441 PetscInt *rsize, *rcone, *rornt, Nt; 8442 8443 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8444 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8445 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8446 numSubcells = rsize[Nt - 1]; 8447 PetscCall(DMPlexTransformDestroy(&tr)); 8448 } 8449 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8450 for (r = 0, q = 0; r < numSubcells; ++r) { 8451 /* TODO Map from coarse to fine cells */ 8452 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8453 /* Compress out points not in the section */ 8454 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8455 for (p = 0; p < numFPoints * 2; p += 2) { 8456 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8457 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8458 if (!dof) continue; 8459 for (s = 0; s < q; ++s) 8460 if (fpoints[p] == ftotpoints[s * 2]) break; 8461 if (s < q) continue; 8462 ftotpoints[q * 2] = fpoints[p]; 8463 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8464 ++q; 8465 } 8466 } 8467 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8468 } 8469 numFPoints = q; 8470 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8471 PetscInt fdof; 8472 8473 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8474 if (!dof) continue; 8475 for (f = 0; f < numFields; ++f) { 8476 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8477 foffsets[f + 1] += fdof; 8478 } 8479 numFIndices += dof; 8480 } 8481 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8482 8483 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8484 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8485 if (numFields) { 8486 const PetscInt **permsF[32] = {NULL}; 8487 const PetscInt **permsC[32] = {NULL}; 8488 8489 for (f = 0; f < numFields; f++) { 8490 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8491 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8492 } 8493 for (p = 0; p < numFPoints; p++) { 8494 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8495 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8496 } 8497 for (p = 0; p < numCPoints; p++) { 8498 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8499 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8500 } 8501 for (f = 0; f < numFields; f++) { 8502 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8503 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8504 } 8505 } else { 8506 const PetscInt **permsF = NULL; 8507 const PetscInt **permsC = NULL; 8508 8509 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8510 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8511 for (p = 0, off = 0; p < numFPoints; p++) { 8512 const PetscInt *perm = permsF ? permsF[p] : NULL; 8513 8514 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8515 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8516 } 8517 for (p = 0, off = 0; p < numCPoints; p++) { 8518 const PetscInt *perm = permsC ? permsC[p] : NULL; 8519 8520 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8521 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8522 } 8523 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8524 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8525 } 8526 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8527 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8528 PetscFunctionReturn(PETSC_SUCCESS); 8529 } 8530 8531 /*@C 8532 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8533 8534 Input Parameter: 8535 . dm - The `DMPLEX` object 8536 8537 Output Parameter: 8538 . cellHeight - The height of a cell 8539 8540 Level: developer 8541 8542 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8543 @*/ 8544 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8545 { 8546 DM_Plex *mesh = (DM_Plex *)dm->data; 8547 8548 PetscFunctionBegin; 8549 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8550 PetscAssertPointer(cellHeight, 2); 8551 *cellHeight = mesh->vtkCellHeight; 8552 PetscFunctionReturn(PETSC_SUCCESS); 8553 } 8554 8555 /*@C 8556 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8557 8558 Input Parameters: 8559 + dm - The `DMPLEX` object 8560 - cellHeight - The height of a cell 8561 8562 Level: developer 8563 8564 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8565 @*/ 8566 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8567 { 8568 DM_Plex *mesh = (DM_Plex *)dm->data; 8569 8570 PetscFunctionBegin; 8571 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8572 mesh->vtkCellHeight = cellHeight; 8573 PetscFunctionReturn(PETSC_SUCCESS); 8574 } 8575 8576 /*@ 8577 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8578 8579 Input Parameters: 8580 + dm - The `DMPLEX` object 8581 - ct - The `DMPolytopeType` of the cell 8582 8583 Output Parameters: 8584 + start - The first cell of this type, or `NULL` 8585 - end - The upper bound on this celltype, or `NULL` 8586 8587 Level: advanced 8588 8589 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8590 @*/ 8591 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8592 { 8593 DM_Plex *mesh = (DM_Plex *)dm->data; 8594 DMLabel label; 8595 PetscInt pStart, pEnd; 8596 8597 PetscFunctionBegin; 8598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8599 if (start) { 8600 PetscAssertPointer(start, 3); 8601 *start = 0; 8602 } 8603 if (end) { 8604 PetscAssertPointer(end, 4); 8605 *end = 0; 8606 } 8607 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8608 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8609 if (mesh->tr) { 8610 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8611 } else { 8612 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8613 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8614 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8615 } 8616 PetscFunctionReturn(PETSC_SUCCESS); 8617 } 8618 8619 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8620 { 8621 PetscSection section, globalSection; 8622 PetscInt *numbers, p; 8623 8624 PetscFunctionBegin; 8625 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8626 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8627 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8628 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8629 PetscCall(PetscSectionSetUp(section)); 8630 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8631 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8632 for (p = pStart; p < pEnd; ++p) { 8633 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8634 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8635 else numbers[p - pStart] += shift; 8636 } 8637 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8638 if (globalSize) { 8639 PetscLayout layout; 8640 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8641 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8642 PetscCall(PetscLayoutDestroy(&layout)); 8643 } 8644 PetscCall(PetscSectionDestroy(§ion)); 8645 PetscCall(PetscSectionDestroy(&globalSection)); 8646 PetscFunctionReturn(PETSC_SUCCESS); 8647 } 8648 8649 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8650 { 8651 PetscInt cellHeight, cStart, cEnd; 8652 8653 PetscFunctionBegin; 8654 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8655 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8656 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8657 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8658 PetscFunctionReturn(PETSC_SUCCESS); 8659 } 8660 8661 /*@ 8662 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8663 8664 Input Parameter: 8665 . dm - The `DMPLEX` object 8666 8667 Output Parameter: 8668 . globalCellNumbers - Global cell numbers for all cells on this process 8669 8670 Level: developer 8671 8672 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8673 @*/ 8674 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8675 { 8676 DM_Plex *mesh = (DM_Plex *)dm->data; 8677 8678 PetscFunctionBegin; 8679 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8680 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8681 *globalCellNumbers = mesh->globalCellNumbers; 8682 PetscFunctionReturn(PETSC_SUCCESS); 8683 } 8684 8685 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8686 { 8687 PetscInt vStart, vEnd; 8688 8689 PetscFunctionBegin; 8690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8691 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8692 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8693 PetscFunctionReturn(PETSC_SUCCESS); 8694 } 8695 8696 /*@ 8697 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8698 8699 Input Parameter: 8700 . dm - The `DMPLEX` object 8701 8702 Output Parameter: 8703 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8704 8705 Level: developer 8706 8707 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8708 @*/ 8709 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8710 { 8711 DM_Plex *mesh = (DM_Plex *)dm->data; 8712 8713 PetscFunctionBegin; 8714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8715 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8716 *globalVertexNumbers = mesh->globalVertexNumbers; 8717 PetscFunctionReturn(PETSC_SUCCESS); 8718 } 8719 8720 /*@ 8721 DMPlexCreatePointNumbering - Create a global numbering for all points. 8722 8723 Collective 8724 8725 Input Parameter: 8726 . dm - The `DMPLEX` object 8727 8728 Output Parameter: 8729 . globalPointNumbers - Global numbers for all points on this process 8730 8731 Level: developer 8732 8733 Notes: 8734 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8735 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8736 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8737 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8738 8739 The partitioned mesh is 8740 ``` 8741 (2)--0--(3)--1--(4) (1)--0--(2) 8742 ``` 8743 and its global numbering is 8744 ``` 8745 (3)--0--(4)--1--(5)--2--(6) 8746 ``` 8747 Then the global numbering is provided as 8748 ``` 8749 [0] Number of indices in set 5 8750 [0] 0 0 8751 [0] 1 1 8752 [0] 2 3 8753 [0] 3 4 8754 [0] 4 -6 8755 [1] Number of indices in set 3 8756 [1] 0 2 8757 [1] 1 5 8758 [1] 2 6 8759 ``` 8760 8761 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8762 @*/ 8763 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8764 { 8765 IS nums[4]; 8766 PetscInt depths[4], gdepths[4], starts[4]; 8767 PetscInt depth, d, shift = 0; 8768 PetscBool empty = PETSC_FALSE; 8769 8770 PetscFunctionBegin; 8771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8772 PetscCall(DMPlexGetDepth(dm, &depth)); 8773 // For unstratified meshes use dim instead of depth 8774 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8775 // If any stratum is empty, we must mark all empty 8776 for (d = 0; d <= depth; ++d) { 8777 PetscInt end; 8778 8779 depths[d] = depth - d; 8780 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8781 if (!(starts[d] - end)) empty = PETSC_TRUE; 8782 } 8783 if (empty) 8784 for (d = 0; d <= depth; ++d) { 8785 depths[d] = -1; 8786 starts[d] = -1; 8787 } 8788 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8789 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8790 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]); 8791 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8792 for (d = 0; d <= depth; ++d) { 8793 PetscInt pStart, pEnd, gsize; 8794 8795 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8796 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8797 shift += gsize; 8798 } 8799 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8800 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8801 PetscFunctionReturn(PETSC_SUCCESS); 8802 } 8803 8804 /*@ 8805 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8806 8807 Input Parameter: 8808 . dm - The `DMPLEX` object 8809 8810 Output Parameter: 8811 . ranks - The rank field 8812 8813 Options Database Key: 8814 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8815 8816 Level: intermediate 8817 8818 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8819 @*/ 8820 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8821 { 8822 DM rdm; 8823 PetscFE fe; 8824 PetscScalar *r; 8825 PetscMPIInt rank; 8826 DMPolytopeType ct; 8827 PetscInt dim, cStart, cEnd, c; 8828 PetscBool simplex; 8829 8830 PetscFunctionBeginUser; 8831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8832 PetscAssertPointer(ranks, 2); 8833 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8834 PetscCall(DMClone(dm, &rdm)); 8835 PetscCall(DMGetDimension(rdm, &dim)); 8836 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8837 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8838 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8839 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8840 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8841 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8842 PetscCall(PetscFEDestroy(&fe)); 8843 PetscCall(DMCreateDS(rdm)); 8844 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8845 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8846 PetscCall(VecGetArray(*ranks, &r)); 8847 for (c = cStart; c < cEnd; ++c) { 8848 PetscScalar *lr; 8849 8850 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8851 if (lr) *lr = rank; 8852 } 8853 PetscCall(VecRestoreArray(*ranks, &r)); 8854 PetscCall(DMDestroy(&rdm)); 8855 PetscFunctionReturn(PETSC_SUCCESS); 8856 } 8857 8858 /*@ 8859 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8860 8861 Input Parameters: 8862 + dm - The `DMPLEX` 8863 - label - The `DMLabel` 8864 8865 Output Parameter: 8866 . val - The label value field 8867 8868 Options Database Key: 8869 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8870 8871 Level: intermediate 8872 8873 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8874 @*/ 8875 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8876 { 8877 DM rdm; 8878 PetscFE fe; 8879 PetscScalar *v; 8880 PetscInt dim, cStart, cEnd, c; 8881 8882 PetscFunctionBeginUser; 8883 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8884 PetscAssertPointer(label, 2); 8885 PetscAssertPointer(val, 3); 8886 PetscCall(DMClone(dm, &rdm)); 8887 PetscCall(DMGetDimension(rdm, &dim)); 8888 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8889 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8890 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8891 PetscCall(PetscFEDestroy(&fe)); 8892 PetscCall(DMCreateDS(rdm)); 8893 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8894 PetscCall(DMCreateGlobalVector(rdm, val)); 8895 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8896 PetscCall(VecGetArray(*val, &v)); 8897 for (c = cStart; c < cEnd; ++c) { 8898 PetscScalar *lv; 8899 PetscInt cval; 8900 8901 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8902 PetscCall(DMLabelGetValue(label, c, &cval)); 8903 *lv = cval; 8904 } 8905 PetscCall(VecRestoreArray(*val, &v)); 8906 PetscCall(DMDestroy(&rdm)); 8907 PetscFunctionReturn(PETSC_SUCCESS); 8908 } 8909 8910 /*@ 8911 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8912 8913 Input Parameter: 8914 . dm - The `DMPLEX` object 8915 8916 Level: developer 8917 8918 Notes: 8919 This is a useful diagnostic when creating meshes programmatically. 8920 8921 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8922 8923 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8924 @*/ 8925 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8926 { 8927 PetscSection coneSection, supportSection; 8928 const PetscInt *cone, *support; 8929 PetscInt coneSize, c, supportSize, s; 8930 PetscInt pStart, pEnd, p, pp, csize, ssize; 8931 PetscBool storagecheck = PETSC_TRUE; 8932 8933 PetscFunctionBegin; 8934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8935 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8936 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8937 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8938 /* Check that point p is found in the support of its cone points, and vice versa */ 8939 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8940 for (p = pStart; p < pEnd; ++p) { 8941 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8942 PetscCall(DMPlexGetCone(dm, p, &cone)); 8943 for (c = 0; c < coneSize; ++c) { 8944 PetscBool dup = PETSC_FALSE; 8945 PetscInt d; 8946 for (d = c - 1; d >= 0; --d) { 8947 if (cone[c] == cone[d]) { 8948 dup = PETSC_TRUE; 8949 break; 8950 } 8951 } 8952 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8953 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8954 for (s = 0; s < supportSize; ++s) { 8955 if (support[s] == p) break; 8956 } 8957 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8958 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8959 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8960 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8961 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8962 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8963 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8964 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]); 8965 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8966 } 8967 } 8968 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8969 if (p != pp) { 8970 storagecheck = PETSC_FALSE; 8971 continue; 8972 } 8973 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8974 PetscCall(DMPlexGetSupport(dm, p, &support)); 8975 for (s = 0; s < supportSize; ++s) { 8976 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8977 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8978 for (c = 0; c < coneSize; ++c) { 8979 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8980 if (cone[c] != pp) { 8981 c = 0; 8982 break; 8983 } 8984 if (cone[c] == p) break; 8985 } 8986 if (c >= coneSize) { 8987 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8988 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8989 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8990 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8991 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8992 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8993 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8994 } 8995 } 8996 } 8997 if (storagecheck) { 8998 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8999 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9000 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9001 } 9002 PetscFunctionReturn(PETSC_SUCCESS); 9003 } 9004 9005 /* 9006 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. 9007 */ 9008 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9009 { 9010 DMPolytopeType cct; 9011 PetscInt ptpoints[4]; 9012 const PetscInt *cone, *ccone, *ptcone; 9013 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9014 9015 PetscFunctionBegin; 9016 *unsplit = 0; 9017 switch (ct) { 9018 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9019 ptpoints[npt++] = c; 9020 break; 9021 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9022 PetscCall(DMPlexGetCone(dm, c, &cone)); 9023 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9024 for (cp = 0; cp < coneSize; ++cp) { 9025 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9026 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9027 } 9028 break; 9029 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9030 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9031 PetscCall(DMPlexGetCone(dm, c, &cone)); 9032 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9033 for (cp = 0; cp < coneSize; ++cp) { 9034 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9035 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9036 for (ccp = 0; ccp < cconeSize; ++ccp) { 9037 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9038 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9039 PetscInt p; 9040 for (p = 0; p < npt; ++p) 9041 if (ptpoints[p] == ccone[ccp]) break; 9042 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9043 } 9044 } 9045 } 9046 break; 9047 default: 9048 break; 9049 } 9050 for (pt = 0; pt < npt; ++pt) { 9051 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9052 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9053 } 9054 PetscFunctionReturn(PETSC_SUCCESS); 9055 } 9056 9057 /*@ 9058 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9059 9060 Input Parameters: 9061 + dm - The `DMPLEX` object 9062 - cellHeight - Normally 0 9063 9064 Level: developer 9065 9066 Notes: 9067 This is a useful diagnostic when creating meshes programmatically. 9068 Currently applicable only to homogeneous simplex or tensor meshes. 9069 9070 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9071 9072 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9073 @*/ 9074 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9075 { 9076 DMPlexInterpolatedFlag interp; 9077 DMPolytopeType ct; 9078 PetscInt vStart, vEnd, cStart, cEnd, c; 9079 9080 PetscFunctionBegin; 9081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9082 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9083 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9084 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9085 for (c = cStart; c < cEnd; ++c) { 9086 PetscInt *closure = NULL; 9087 PetscInt coneSize, closureSize, cl, Nv = 0; 9088 9089 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9090 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9091 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9092 if (interp == DMPLEX_INTERPOLATED_FULL) { 9093 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9094 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)); 9095 } 9096 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9097 for (cl = 0; cl < closureSize * 2; cl += 2) { 9098 const PetscInt p = closure[cl]; 9099 if ((p >= vStart) && (p < vEnd)) ++Nv; 9100 } 9101 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9102 /* Special Case: Tensor faces with identified vertices */ 9103 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9104 PetscInt unsplit; 9105 9106 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9107 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9108 } 9109 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)); 9110 } 9111 PetscFunctionReturn(PETSC_SUCCESS); 9112 } 9113 9114 /*@ 9115 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9116 9117 Collective 9118 9119 Input Parameters: 9120 + dm - The `DMPLEX` object 9121 - cellHeight - Normally 0 9122 9123 Level: developer 9124 9125 Notes: 9126 This is a useful diagnostic when creating meshes programmatically. 9127 This routine is only relevant for meshes that are fully interpolated across all ranks. 9128 It will error out if a partially interpolated mesh is given on some rank. 9129 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9130 9131 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9132 9133 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9134 @*/ 9135 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9136 { 9137 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9138 DMPlexInterpolatedFlag interpEnum; 9139 9140 PetscFunctionBegin; 9141 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9142 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9143 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9144 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9145 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9146 PetscFunctionReturn(PETSC_SUCCESS); 9147 } 9148 9149 PetscCall(DMGetDimension(dm, &dim)); 9150 PetscCall(DMPlexGetDepth(dm, &depth)); 9151 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9152 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9153 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9154 for (c = cStart; c < cEnd; ++c) { 9155 const PetscInt *cone, *ornt, *faceSizes, *faces; 9156 const DMPolytopeType *faceTypes; 9157 DMPolytopeType ct; 9158 PetscInt numFaces, coneSize, f; 9159 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9160 9161 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9162 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9163 if (unsplit) continue; 9164 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9165 PetscCall(DMPlexGetCone(dm, c, &cone)); 9166 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9167 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9168 for (cl = 0; cl < closureSize * 2; cl += 2) { 9169 const PetscInt p = closure[cl]; 9170 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9171 } 9172 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9173 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); 9174 for (f = 0; f < numFaces; ++f) { 9175 DMPolytopeType fct; 9176 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9177 9178 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9179 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9180 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9181 const PetscInt p = fclosure[cl]; 9182 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9183 } 9184 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]); 9185 for (v = 0; v < fnumCorners; ++v) { 9186 if (fclosure[v] != faces[fOff + v]) { 9187 PetscInt v1; 9188 9189 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9190 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9191 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9192 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9193 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9194 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]); 9195 } 9196 } 9197 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9198 fOff += faceSizes[f]; 9199 } 9200 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9201 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9202 } 9203 } 9204 PetscFunctionReturn(PETSC_SUCCESS); 9205 } 9206 9207 /*@ 9208 DMPlexCheckGeometry - Check the geometry of mesh cells 9209 9210 Input Parameter: 9211 . dm - The `DMPLEX` object 9212 9213 Level: developer 9214 9215 Notes: 9216 This is a useful diagnostic when creating meshes programmatically. 9217 9218 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9219 9220 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9221 @*/ 9222 PetscErrorCode DMPlexCheckGeometry(DM dm) 9223 { 9224 Vec coordinates; 9225 PetscReal detJ, J[9], refVol = 1.0; 9226 PetscReal vol; 9227 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9228 9229 PetscFunctionBegin; 9230 PetscCall(DMGetDimension(dm, &dim)); 9231 PetscCall(DMGetCoordinateDim(dm, &dE)); 9232 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9233 PetscCall(DMPlexGetDepth(dm, &depth)); 9234 for (d = 0; d < dim; ++d) refVol *= 2.0; 9235 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9236 /* Make sure local coordinates are created, because that step is collective */ 9237 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9238 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9239 for (c = cStart; c < cEnd; ++c) { 9240 DMPolytopeType ct; 9241 PetscInt unsplit; 9242 PetscBool ignoreZeroVol = PETSC_FALSE; 9243 9244 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9245 switch (ct) { 9246 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9247 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9248 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9249 ignoreZeroVol = PETSC_TRUE; 9250 break; 9251 default: 9252 break; 9253 } 9254 switch (ct) { 9255 case DM_POLYTOPE_TRI_PRISM: 9256 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9257 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9258 case DM_POLYTOPE_PYRAMID: 9259 continue; 9260 default: 9261 break; 9262 } 9263 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9264 if (unsplit) continue; 9265 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9266 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); 9267 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9268 /* This should work with periodicity since DG coordinates should be used */ 9269 if (depth > 1) { 9270 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9271 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); 9272 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9273 } 9274 } 9275 PetscFunctionReturn(PETSC_SUCCESS); 9276 } 9277 9278 /*@ 9279 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9280 9281 Collective 9282 9283 Input Parameters: 9284 + dm - The `DMPLEX` object 9285 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9286 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9287 9288 Level: developer 9289 9290 Notes: 9291 This is mainly intended for debugging/testing purposes. 9292 9293 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9294 9295 Extra roots can come from periodic cuts, where additional points appear on the boundary 9296 9297 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9298 @*/ 9299 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9300 { 9301 PetscInt l, nleaves, nroots, overlap; 9302 const PetscInt *locals; 9303 const PetscSFNode *remotes; 9304 PetscBool distributed; 9305 MPI_Comm comm; 9306 PetscMPIInt rank; 9307 9308 PetscFunctionBegin; 9309 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9310 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9311 else pointSF = dm->sf; 9312 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9313 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9314 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9315 { 9316 PetscMPIInt mpiFlag; 9317 9318 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9319 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9320 } 9321 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9322 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9323 if (!distributed) { 9324 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); 9325 PetscFunctionReturn(PETSC_SUCCESS); 9326 } 9327 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); 9328 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9329 9330 /* Check SF graph is compatible with DMPlex chart */ 9331 { 9332 PetscInt pStart, pEnd, maxLeaf; 9333 9334 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9335 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9336 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9337 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9338 } 9339 9340 /* Check Point SF has no local points referenced */ 9341 for (l = 0; l < nleaves; l++) { 9342 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); 9343 } 9344 9345 /* Check there are no cells in interface */ 9346 if (!overlap) { 9347 PetscInt cellHeight, cStart, cEnd; 9348 9349 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9350 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9351 for (l = 0; l < nleaves; ++l) { 9352 const PetscInt point = locals ? locals[l] : l; 9353 9354 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9355 } 9356 } 9357 9358 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9359 { 9360 const PetscInt *rootdegree; 9361 9362 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9363 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9364 for (l = 0; l < nleaves; ++l) { 9365 const PetscInt point = locals ? locals[l] : l; 9366 const PetscInt *cone; 9367 PetscInt coneSize, c, idx; 9368 9369 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9370 PetscCall(DMPlexGetCone(dm, point, &cone)); 9371 for (c = 0; c < coneSize; ++c) { 9372 if (!rootdegree[cone[c]]) { 9373 if (locals) { 9374 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9375 } else { 9376 idx = (cone[c] < nleaves) ? cone[c] : -1; 9377 } 9378 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9379 } 9380 } 9381 } 9382 } 9383 PetscFunctionReturn(PETSC_SUCCESS); 9384 } 9385 9386 /*@ 9387 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9388 9389 Input Parameter: 9390 . dm - The `DMPLEX` object 9391 9392 Level: developer 9393 9394 Notes: 9395 This is a useful diagnostic when creating meshes programmatically. 9396 9397 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9398 9399 Currently does not include `DMPlexCheckCellShape()`. 9400 9401 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9402 @*/ 9403 PetscErrorCode DMPlexCheck(DM dm) 9404 { 9405 PetscInt cellHeight; 9406 9407 PetscFunctionBegin; 9408 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9409 PetscCall(DMPlexCheckSymmetry(dm)); 9410 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9411 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9412 PetscCall(DMPlexCheckGeometry(dm)); 9413 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9414 PetscCall(DMPlexCheckInterfaceCones(dm)); 9415 PetscFunctionReturn(PETSC_SUCCESS); 9416 } 9417 9418 typedef struct cell_stats { 9419 PetscReal min, max, sum, squaresum; 9420 PetscInt count; 9421 } cell_stats_t; 9422 9423 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9424 { 9425 PetscInt i, N = *len; 9426 9427 for (i = 0; i < N; i++) { 9428 cell_stats_t *A = (cell_stats_t *)a; 9429 cell_stats_t *B = (cell_stats_t *)b; 9430 9431 B->min = PetscMin(A->min, B->min); 9432 B->max = PetscMax(A->max, B->max); 9433 B->sum += A->sum; 9434 B->squaresum += A->squaresum; 9435 B->count += A->count; 9436 } 9437 } 9438 9439 /*@ 9440 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9441 9442 Collective 9443 9444 Input Parameters: 9445 + dm - The `DMPLEX` object 9446 . output - If true, statistics will be displayed on `stdout` 9447 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9448 9449 Level: developer 9450 9451 Notes: 9452 This is mainly intended for debugging/testing purposes. 9453 9454 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9455 9456 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9457 @*/ 9458 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9459 { 9460 DM dmCoarse; 9461 cell_stats_t stats, globalStats; 9462 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9463 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9464 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9465 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9466 PetscMPIInt rank, size; 9467 9468 PetscFunctionBegin; 9469 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9470 stats.min = PETSC_MAX_REAL; 9471 stats.max = PETSC_MIN_REAL; 9472 stats.sum = stats.squaresum = 0.; 9473 stats.count = 0; 9474 9475 PetscCallMPI(MPI_Comm_size(comm, &size)); 9476 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9477 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9478 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9479 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9480 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9481 for (c = cStart; c < cEnd; c++) { 9482 PetscInt i; 9483 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9484 9485 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9486 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9487 for (i = 0; i < PetscSqr(cdim); ++i) { 9488 frobJ += J[i] * J[i]; 9489 frobInvJ += invJ[i] * invJ[i]; 9490 } 9491 cond2 = frobJ * frobInvJ; 9492 cond = PetscSqrtReal(cond2); 9493 9494 stats.min = PetscMin(stats.min, cond); 9495 stats.max = PetscMax(stats.max, cond); 9496 stats.sum += cond; 9497 stats.squaresum += cond2; 9498 stats.count++; 9499 if (output && cond > limit) { 9500 PetscSection coordSection; 9501 Vec coordsLocal; 9502 PetscScalar *coords = NULL; 9503 PetscInt Nv, d, clSize, cl, *closure = NULL; 9504 9505 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9506 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9507 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9508 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9509 for (i = 0; i < Nv / cdim; ++i) { 9510 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9511 for (d = 0; d < cdim; ++d) { 9512 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9513 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9514 } 9515 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9516 } 9517 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9518 for (cl = 0; cl < clSize * 2; cl += 2) { 9519 const PetscInt edge = closure[cl]; 9520 9521 if ((edge >= eStart) && (edge < eEnd)) { 9522 PetscReal len; 9523 9524 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9525 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9526 } 9527 } 9528 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9529 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9530 } 9531 } 9532 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9533 9534 if (size > 1) { 9535 PetscMPIInt blockLengths[2] = {4, 1}; 9536 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9537 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9538 MPI_Op statReduce; 9539 9540 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9541 PetscCallMPI(MPI_Type_commit(&statType)); 9542 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9543 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9544 PetscCallMPI(MPI_Op_free(&statReduce)); 9545 PetscCallMPI(MPI_Type_free(&statType)); 9546 } else { 9547 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9548 } 9549 if (rank == 0) { 9550 count = globalStats.count; 9551 min = globalStats.min; 9552 max = globalStats.max; 9553 mean = globalStats.sum / globalStats.count; 9554 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9555 } 9556 9557 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)); 9558 PetscCall(PetscFree2(J, invJ)); 9559 9560 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9561 if (dmCoarse) { 9562 PetscBool isplex; 9563 9564 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9565 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9566 } 9567 PetscFunctionReturn(PETSC_SUCCESS); 9568 } 9569 9570 /*@ 9571 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9572 orthogonal quality below given tolerance. 9573 9574 Collective 9575 9576 Input Parameters: 9577 + dm - The `DMPLEX` object 9578 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9579 - atol - [0, 1] Absolute tolerance for tagging cells. 9580 9581 Output Parameters: 9582 + OrthQual - `Vec` containing orthogonal quality per cell 9583 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9584 9585 Options Database Keys: 9586 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9587 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9588 9589 Level: intermediate 9590 9591 Notes: 9592 Orthogonal quality is given by the following formula\: 9593 9594 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9595 9596 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 9597 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9598 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9599 calculating the cosine of the angle between these vectors. 9600 9601 Orthogonal quality ranges from 1 (best) to 0 (worst). 9602 9603 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9604 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9605 9606 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9607 9608 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9609 @*/ 9610 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9611 { 9612 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9613 PetscInt *idx; 9614 PetscScalar *oqVals; 9615 const PetscScalar *cellGeomArr, *faceGeomArr; 9616 PetscReal *ci, *fi, *Ai; 9617 MPI_Comm comm; 9618 Vec cellgeom, facegeom; 9619 DM dmFace, dmCell; 9620 IS glob; 9621 ISLocalToGlobalMapping ltog; 9622 PetscViewer vwr; 9623 9624 PetscFunctionBegin; 9625 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9626 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9627 PetscAssertPointer(OrthQual, 4); 9628 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9629 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9630 PetscCall(DMGetDimension(dm, &nc)); 9631 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9632 { 9633 DMPlexInterpolatedFlag interpFlag; 9634 9635 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9636 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9637 PetscMPIInt rank; 9638 9639 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9640 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9641 } 9642 } 9643 if (OrthQualLabel) { 9644 PetscAssertPointer(OrthQualLabel, 5); 9645 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9646 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9647 } else { 9648 *OrthQualLabel = NULL; 9649 } 9650 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9651 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9652 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9653 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9654 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9655 PetscCall(VecCreate(comm, OrthQual)); 9656 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9657 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9658 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9659 PetscCall(VecSetUp(*OrthQual)); 9660 PetscCall(ISDestroy(&glob)); 9661 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9662 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9663 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9664 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9665 PetscCall(VecGetDM(cellgeom, &dmCell)); 9666 PetscCall(VecGetDM(facegeom, &dmFace)); 9667 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9668 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9669 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9670 PetscInt cellarr[2], *adj = NULL; 9671 PetscScalar *cArr, *fArr; 9672 PetscReal minvalc = 1.0, minvalf = 1.0; 9673 PetscFVCellGeom *cg; 9674 9675 idx[cellIter] = cell - cStart; 9676 cellarr[0] = cell; 9677 /* Make indexing into cellGeom easier */ 9678 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9679 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9680 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9681 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9682 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9683 PetscInt i; 9684 const PetscInt neigh = adj[cellneigh]; 9685 PetscReal normci = 0, normfi = 0, normai = 0; 9686 PetscFVCellGeom *cgneigh; 9687 PetscFVFaceGeom *fg; 9688 9689 /* Don't count ourselves in the neighbor list */ 9690 if (neigh == cell) continue; 9691 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9692 cellarr[1] = neigh; 9693 { 9694 PetscInt numcovpts; 9695 const PetscInt *covpts; 9696 9697 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9698 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9699 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9700 } 9701 9702 /* Compute c_i, f_i and their norms */ 9703 for (i = 0; i < nc; i++) { 9704 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9705 fi[i] = fg->centroid[i] - cg->centroid[i]; 9706 Ai[i] = fg->normal[i]; 9707 normci += PetscPowReal(ci[i], 2); 9708 normfi += PetscPowReal(fi[i], 2); 9709 normai += PetscPowReal(Ai[i], 2); 9710 } 9711 normci = PetscSqrtReal(normci); 9712 normfi = PetscSqrtReal(normfi); 9713 normai = PetscSqrtReal(normai); 9714 9715 /* Normalize and compute for each face-cell-normal pair */ 9716 for (i = 0; i < nc; i++) { 9717 ci[i] = ci[i] / normci; 9718 fi[i] = fi[i] / normfi; 9719 Ai[i] = Ai[i] / normai; 9720 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9721 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9722 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9723 } 9724 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9725 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9726 } 9727 PetscCall(PetscFree(adj)); 9728 PetscCall(PetscFree2(cArr, fArr)); 9729 /* Defer to cell if they're equal */ 9730 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9731 if (OrthQualLabel) { 9732 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9733 } 9734 } 9735 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9736 PetscCall(VecAssemblyBegin(*OrthQual)); 9737 PetscCall(VecAssemblyEnd(*OrthQual)); 9738 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9739 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9740 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9741 if (OrthQualLabel) { 9742 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9743 } 9744 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9745 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9746 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9747 PetscFunctionReturn(PETSC_SUCCESS); 9748 } 9749 9750 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9751 * interpolator construction */ 9752 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9753 { 9754 PetscSection section, newSection, gsection; 9755 PetscSF sf; 9756 PetscBool hasConstraints, ghasConstraints; 9757 9758 PetscFunctionBegin; 9759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9760 PetscAssertPointer(odm, 2); 9761 PetscCall(DMGetLocalSection(dm, §ion)); 9762 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9763 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9764 if (!ghasConstraints) { 9765 PetscCall(PetscObjectReference((PetscObject)dm)); 9766 *odm = dm; 9767 PetscFunctionReturn(PETSC_SUCCESS); 9768 } 9769 PetscCall(DMClone(dm, odm)); 9770 PetscCall(DMCopyFields(dm, *odm)); 9771 PetscCall(DMGetLocalSection(*odm, &newSection)); 9772 PetscCall(DMGetPointSF(*odm, &sf)); 9773 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9774 PetscCall(DMSetGlobalSection(*odm, gsection)); 9775 PetscCall(PetscSectionDestroy(&gsection)); 9776 PetscFunctionReturn(PETSC_SUCCESS); 9777 } 9778 9779 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9780 { 9781 DM dmco, dmfo; 9782 Mat interpo; 9783 Vec rscale; 9784 Vec cglobalo, clocal; 9785 Vec fglobal, fglobalo, flocal; 9786 PetscBool regular; 9787 9788 PetscFunctionBegin; 9789 PetscCall(DMGetFullDM(dmc, &dmco)); 9790 PetscCall(DMGetFullDM(dmf, &dmfo)); 9791 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9792 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9793 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9794 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9795 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9796 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9797 PetscCall(VecSet(cglobalo, 0.)); 9798 PetscCall(VecSet(clocal, 0.)); 9799 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9800 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9801 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9802 PetscCall(VecSet(fglobal, 0.)); 9803 PetscCall(VecSet(fglobalo, 0.)); 9804 PetscCall(VecSet(flocal, 0.)); 9805 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9806 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9807 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9808 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9809 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9810 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9811 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9812 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9813 *shift = fglobal; 9814 PetscCall(VecDestroy(&flocal)); 9815 PetscCall(VecDestroy(&fglobalo)); 9816 PetscCall(VecDestroy(&clocal)); 9817 PetscCall(VecDestroy(&cglobalo)); 9818 PetscCall(VecDestroy(&rscale)); 9819 PetscCall(MatDestroy(&interpo)); 9820 PetscCall(DMDestroy(&dmfo)); 9821 PetscCall(DMDestroy(&dmco)); 9822 PetscFunctionReturn(PETSC_SUCCESS); 9823 } 9824 9825 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9826 { 9827 PetscObject shifto; 9828 Vec shift; 9829 9830 PetscFunctionBegin; 9831 if (!interp) { 9832 Vec rscale; 9833 9834 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9835 PetscCall(VecDestroy(&rscale)); 9836 } else { 9837 PetscCall(PetscObjectReference((PetscObject)interp)); 9838 } 9839 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9840 if (!shifto) { 9841 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9842 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9843 shifto = (PetscObject)shift; 9844 PetscCall(VecDestroy(&shift)); 9845 } 9846 shift = (Vec)shifto; 9847 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9848 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9849 PetscCall(MatDestroy(&interp)); 9850 PetscFunctionReturn(PETSC_SUCCESS); 9851 } 9852 9853 /* Pointwise interpolation 9854 Just code FEM for now 9855 u^f = I u^c 9856 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9857 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9858 I_{ij} = psi^f_i phi^c_j 9859 */ 9860 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9861 { 9862 PetscSection gsc, gsf; 9863 PetscInt m, n; 9864 void *ctx; 9865 DM cdm; 9866 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9867 9868 PetscFunctionBegin; 9869 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9870 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9871 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9872 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9873 9874 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9875 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9876 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9877 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9878 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9879 9880 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9881 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9882 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9883 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9884 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9885 if (scaling) { 9886 /* Use naive scaling */ 9887 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9888 } 9889 PetscFunctionReturn(PETSC_SUCCESS); 9890 } 9891 9892 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9893 { 9894 VecScatter ctx; 9895 9896 PetscFunctionBegin; 9897 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9898 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9899 PetscCall(VecScatterDestroy(&ctx)); 9900 PetscFunctionReturn(PETSC_SUCCESS); 9901 } 9902 9903 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[]) 9904 { 9905 const PetscInt Nc = uOff[1] - uOff[0]; 9906 PetscInt c; 9907 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9908 } 9909 9910 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9911 { 9912 DM dmc; 9913 PetscDS ds; 9914 Vec ones, locmass; 9915 IS cellIS; 9916 PetscFormKey key; 9917 PetscInt depth; 9918 9919 PetscFunctionBegin; 9920 PetscCall(DMClone(dm, &dmc)); 9921 PetscCall(DMCopyDisc(dm, dmc)); 9922 PetscCall(DMGetDS(dmc, &ds)); 9923 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9924 PetscCall(DMCreateGlobalVector(dmc, mass)); 9925 PetscCall(DMGetLocalVector(dmc, &ones)); 9926 PetscCall(DMGetLocalVector(dmc, &locmass)); 9927 PetscCall(DMPlexGetDepth(dmc, &depth)); 9928 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9929 PetscCall(VecSet(locmass, 0.0)); 9930 PetscCall(VecSet(ones, 1.0)); 9931 key.label = NULL; 9932 key.value = 0; 9933 key.field = 0; 9934 key.part = 0; 9935 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9936 PetscCall(ISDestroy(&cellIS)); 9937 PetscCall(VecSet(*mass, 0.0)); 9938 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9939 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9940 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9941 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9942 PetscCall(DMDestroy(&dmc)); 9943 PetscFunctionReturn(PETSC_SUCCESS); 9944 } 9945 9946 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9947 { 9948 PetscSection gsc, gsf; 9949 PetscInt m, n; 9950 void *ctx; 9951 DM cdm; 9952 PetscBool regular; 9953 9954 PetscFunctionBegin; 9955 if (dmFine == dmCoarse) { 9956 DM dmc; 9957 PetscDS ds; 9958 PetscWeakForm wf; 9959 Vec u; 9960 IS cellIS; 9961 PetscFormKey key; 9962 PetscInt depth; 9963 9964 PetscCall(DMClone(dmFine, &dmc)); 9965 PetscCall(DMCopyDisc(dmFine, dmc)); 9966 PetscCall(DMGetDS(dmc, &ds)); 9967 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9968 PetscCall(PetscWeakFormClear(wf)); 9969 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9970 PetscCall(DMCreateMatrix(dmc, mass)); 9971 PetscCall(DMGetLocalVector(dmc, &u)); 9972 PetscCall(DMPlexGetDepth(dmc, &depth)); 9973 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9974 PetscCall(MatZeroEntries(*mass)); 9975 key.label = NULL; 9976 key.value = 0; 9977 key.field = 0; 9978 key.part = 0; 9979 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9980 PetscCall(ISDestroy(&cellIS)); 9981 PetscCall(DMRestoreLocalVector(dmc, &u)); 9982 PetscCall(DMDestroy(&dmc)); 9983 } else { 9984 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9985 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9986 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9987 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9988 9989 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9990 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9991 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9992 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9993 9994 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9995 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9996 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9997 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9998 } 9999 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10000 PetscFunctionReturn(PETSC_SUCCESS); 10001 } 10002 10003 /*@ 10004 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10005 10006 Input Parameter: 10007 . dm - The `DMPLEX` object 10008 10009 Output Parameter: 10010 . regular - The flag 10011 10012 Level: intermediate 10013 10014 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10015 @*/ 10016 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10017 { 10018 PetscFunctionBegin; 10019 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10020 PetscAssertPointer(regular, 2); 10021 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10022 PetscFunctionReturn(PETSC_SUCCESS); 10023 } 10024 10025 /*@ 10026 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10027 10028 Input Parameters: 10029 + dm - The `DMPLEX` object 10030 - regular - The flag 10031 10032 Level: intermediate 10033 10034 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10035 @*/ 10036 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10037 { 10038 PetscFunctionBegin; 10039 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10040 ((DM_Plex *)dm->data)->regularRefinement = regular; 10041 PetscFunctionReturn(PETSC_SUCCESS); 10042 } 10043 10044 /*@ 10045 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10046 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10047 10048 Not Collective 10049 10050 Input Parameter: 10051 . dm - The `DMPLEX` object 10052 10053 Output Parameters: 10054 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10055 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10056 10057 Level: intermediate 10058 10059 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10060 @*/ 10061 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10062 { 10063 DM_Plex *plex = (DM_Plex *)dm->data; 10064 10065 PetscFunctionBegin; 10066 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10067 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10068 if (anchorSection) *anchorSection = plex->anchorSection; 10069 if (anchorIS) *anchorIS = plex->anchorIS; 10070 PetscFunctionReturn(PETSC_SUCCESS); 10071 } 10072 10073 /*@ 10074 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10075 10076 Collective 10077 10078 Input Parameters: 10079 + dm - The `DMPLEX` object 10080 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10081 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10082 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10083 10084 Level: intermediate 10085 10086 Notes: 10087 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10088 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10089 combination of other points' degrees of freedom. 10090 10091 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10092 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10093 10094 The reference counts of `anchorSection` and `anchorIS` are incremented. 10095 10096 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10097 @*/ 10098 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10099 { 10100 DM_Plex *plex = (DM_Plex *)dm->data; 10101 PetscMPIInt result; 10102 10103 PetscFunctionBegin; 10104 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10105 if (anchorSection) { 10106 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10107 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10108 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10109 } 10110 if (anchorIS) { 10111 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10112 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10113 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10114 } 10115 10116 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10117 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10118 plex->anchorSection = anchorSection; 10119 10120 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10121 PetscCall(ISDestroy(&plex->anchorIS)); 10122 plex->anchorIS = anchorIS; 10123 10124 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10125 PetscInt size, a, pStart, pEnd; 10126 const PetscInt *anchors; 10127 10128 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10129 PetscCall(ISGetLocalSize(anchorIS, &size)); 10130 PetscCall(ISGetIndices(anchorIS, &anchors)); 10131 for (a = 0; a < size; a++) { 10132 PetscInt p; 10133 10134 p = anchors[a]; 10135 if (p >= pStart && p < pEnd) { 10136 PetscInt dof; 10137 10138 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10139 if (dof) { 10140 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10141 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10142 } 10143 } 10144 } 10145 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10146 } 10147 /* reset the generic constraints */ 10148 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10149 PetscFunctionReturn(PETSC_SUCCESS); 10150 } 10151 10152 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10153 { 10154 PetscSection anchorSection; 10155 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10156 10157 PetscFunctionBegin; 10158 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10159 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10160 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10161 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10162 if (numFields) { 10163 PetscInt f; 10164 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10165 10166 for (f = 0; f < numFields; f++) { 10167 PetscInt numComp; 10168 10169 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10170 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10171 } 10172 } 10173 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10174 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10175 pStart = PetscMax(pStart, sStart); 10176 pEnd = PetscMin(pEnd, sEnd); 10177 pEnd = PetscMax(pStart, pEnd); 10178 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10179 for (p = pStart; p < pEnd; p++) { 10180 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10181 if (dof) { 10182 PetscCall(PetscSectionGetDof(section, p, &dof)); 10183 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10184 for (f = 0; f < numFields; f++) { 10185 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10186 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10187 } 10188 } 10189 } 10190 PetscCall(PetscSectionSetUp(*cSec)); 10191 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10192 PetscFunctionReturn(PETSC_SUCCESS); 10193 } 10194 10195 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10196 { 10197 PetscSection aSec; 10198 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10199 const PetscInt *anchors; 10200 PetscInt numFields, f; 10201 IS aIS; 10202 MatType mtype; 10203 PetscBool iscuda, iskokkos; 10204 10205 PetscFunctionBegin; 10206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10207 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10208 PetscCall(PetscSectionGetStorageSize(section, &n)); 10209 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10210 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10211 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10212 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10213 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10214 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10215 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10216 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10217 else mtype = MATSEQAIJ; 10218 PetscCall(MatSetType(*cMat, mtype)); 10219 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10220 PetscCall(ISGetIndices(aIS, &anchors)); 10221 /* cSec will be a subset of aSec and section */ 10222 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10223 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10224 PetscCall(PetscMalloc1(m + 1, &i)); 10225 i[0] = 0; 10226 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10227 for (p = pStart; p < pEnd; p++) { 10228 PetscInt rDof, rOff, r; 10229 10230 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10231 if (!rDof) continue; 10232 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10233 if (numFields) { 10234 for (f = 0; f < numFields; f++) { 10235 annz = 0; 10236 for (r = 0; r < rDof; r++) { 10237 a = anchors[rOff + r]; 10238 if (a < sStart || a >= sEnd) continue; 10239 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10240 annz += aDof; 10241 } 10242 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10243 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10244 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10245 } 10246 } else { 10247 annz = 0; 10248 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10249 for (q = 0; q < dof; q++) { 10250 a = anchors[rOff + q]; 10251 if (a < sStart || a >= sEnd) continue; 10252 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10253 annz += aDof; 10254 } 10255 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10256 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10257 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10258 } 10259 } 10260 nnz = i[m]; 10261 PetscCall(PetscMalloc1(nnz, &j)); 10262 offset = 0; 10263 for (p = pStart; p < pEnd; p++) { 10264 if (numFields) { 10265 for (f = 0; f < numFields; f++) { 10266 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10267 for (q = 0; q < dof; q++) { 10268 PetscInt rDof, rOff, r; 10269 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10270 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10271 for (r = 0; r < rDof; r++) { 10272 PetscInt s; 10273 10274 a = anchors[rOff + r]; 10275 if (a < sStart || a >= sEnd) continue; 10276 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10277 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10278 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10279 } 10280 } 10281 } 10282 } else { 10283 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10284 for (q = 0; q < dof; q++) { 10285 PetscInt rDof, rOff, r; 10286 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10287 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10288 for (r = 0; r < rDof; r++) { 10289 PetscInt s; 10290 10291 a = anchors[rOff + r]; 10292 if (a < sStart || a >= sEnd) continue; 10293 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10294 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10295 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10296 } 10297 } 10298 } 10299 } 10300 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10301 PetscCall(PetscFree(i)); 10302 PetscCall(PetscFree(j)); 10303 PetscCall(ISRestoreIndices(aIS, &anchors)); 10304 PetscFunctionReturn(PETSC_SUCCESS); 10305 } 10306 10307 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10308 { 10309 DM_Plex *plex = (DM_Plex *)dm->data; 10310 PetscSection anchorSection, section, cSec; 10311 Mat cMat; 10312 10313 PetscFunctionBegin; 10314 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10315 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10316 if (anchorSection) { 10317 PetscInt Nf; 10318 10319 PetscCall(DMGetLocalSection(dm, §ion)); 10320 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10321 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10322 PetscCall(DMGetNumFields(dm, &Nf)); 10323 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10324 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10325 PetscCall(PetscSectionDestroy(&cSec)); 10326 PetscCall(MatDestroy(&cMat)); 10327 } 10328 PetscFunctionReturn(PETSC_SUCCESS); 10329 } 10330 10331 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10332 { 10333 IS subis; 10334 PetscSection section, subsection; 10335 10336 PetscFunctionBegin; 10337 PetscCall(DMGetLocalSection(dm, §ion)); 10338 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10339 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10340 /* Create subdomain */ 10341 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10342 /* Create submodel */ 10343 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10344 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10345 PetscCall(DMSetLocalSection(*subdm, subsection)); 10346 PetscCall(PetscSectionDestroy(&subsection)); 10347 PetscCall(DMCopyDisc(dm, *subdm)); 10348 /* Create map from submodel to global model */ 10349 if (is) { 10350 PetscSection sectionGlobal, subsectionGlobal; 10351 IS spIS; 10352 const PetscInt *spmap; 10353 PetscInt *subIndices; 10354 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10355 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10356 10357 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10358 PetscCall(ISGetIndices(spIS, &spmap)); 10359 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10360 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10361 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10362 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10363 for (p = pStart; p < pEnd; ++p) { 10364 PetscInt gdof, pSubSize = 0; 10365 10366 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10367 if (gdof > 0) { 10368 for (f = 0; f < Nf; ++f) { 10369 PetscInt fdof, fcdof; 10370 10371 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10372 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10373 pSubSize += fdof - fcdof; 10374 } 10375 subSize += pSubSize; 10376 if (pSubSize) { 10377 if (bs < 0) { 10378 bs = pSubSize; 10379 } else if (bs != pSubSize) { 10380 /* Layout does not admit a pointwise block size */ 10381 bs = 1; 10382 } 10383 } 10384 } 10385 } 10386 /* Must have same blocksize on all procs (some might have no points) */ 10387 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10388 bsLocal[1] = bs; 10389 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10390 if (bsMinMax[0] != bsMinMax[1]) { 10391 bs = 1; 10392 } else { 10393 bs = bsMinMax[0]; 10394 } 10395 PetscCall(PetscMalloc1(subSize, &subIndices)); 10396 for (p = pStart; p < pEnd; ++p) { 10397 PetscInt gdof, goff; 10398 10399 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10400 if (gdof > 0) { 10401 const PetscInt point = spmap[p]; 10402 10403 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10404 for (f = 0; f < Nf; ++f) { 10405 PetscInt fdof, fcdof, fc, f2, poff = 0; 10406 10407 /* Can get rid of this loop by storing field information in the global section */ 10408 for (f2 = 0; f2 < f; ++f2) { 10409 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10410 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10411 poff += fdof - fcdof; 10412 } 10413 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10414 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10415 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10416 } 10417 } 10418 } 10419 PetscCall(ISRestoreIndices(spIS, &spmap)); 10420 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10421 if (bs > 1) { 10422 /* We need to check that the block size does not come from non-contiguous fields */ 10423 PetscInt i, j, set = 1; 10424 for (i = 0; i < subSize; i += bs) { 10425 for (j = 0; j < bs; ++j) { 10426 if (subIndices[i + j] != subIndices[i] + j) { 10427 set = 0; 10428 break; 10429 } 10430 } 10431 } 10432 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10433 } 10434 /* Attach nullspace */ 10435 for (f = 0; f < Nf; ++f) { 10436 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10437 if ((*subdm)->nullspaceConstructors[f]) break; 10438 } 10439 if (f < Nf) { 10440 MatNullSpace nullSpace; 10441 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10442 10443 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10444 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10445 } 10446 } 10447 PetscFunctionReturn(PETSC_SUCCESS); 10448 } 10449 10450 /*@ 10451 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10452 10453 Input Parameters: 10454 + dm - The `DM` 10455 - dummy - unused argument 10456 10457 Options Database Key: 10458 . -dm_plex_monitor_throughput - Activate the monitor 10459 10460 Level: developer 10461 10462 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10463 @*/ 10464 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10465 { 10466 PetscLogHandler default_handler; 10467 10468 PetscFunctionBegin; 10469 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10470 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10471 if (default_handler) { 10472 PetscLogEvent event; 10473 PetscEventPerfInfo eventInfo; 10474 PetscReal cellRate, flopRate; 10475 PetscInt cStart, cEnd, Nf, N; 10476 const char *name; 10477 10478 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10479 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10480 PetscCall(DMGetNumFields(dm, &Nf)); 10481 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10482 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10483 N = (cEnd - cStart) * Nf * eventInfo.count; 10484 flopRate = eventInfo.flops / eventInfo.time; 10485 cellRate = N / eventInfo.time; 10486 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))); 10487 } else { 10488 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."); 10489 } 10490 PetscFunctionReturn(PETSC_SUCCESS); 10491 } 10492