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