1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 15 16 PetscBool Plexcite = PETSC_FALSE; 17 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 18 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 19 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 20 "journal = {SIAM Journal on Scientific Computing},\n" 21 "volume = {38},\n" 22 "number = {5},\n" 23 "pages = {S143--S155},\n" 24 "eprint = {http://arxiv.org/abs/1506.07749},\n" 25 "doi = {10.1137/15M1026092},\n" 26 "year = {2016},\n" 27 "petsc_uses={DMPlex},\n}\n"; 28 29 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 30 31 /*@ 32 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 33 34 Input Parameter: 35 . dm - The `DMPLEX` object 36 37 Output Parameter: 38 . simplex - Flag checking for a simplex 39 40 Level: intermediate 41 42 Note: 43 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 44 If the mesh has no cells, this returns `PETSC_FALSE`. 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 47 @*/ 48 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 49 { 50 DMPolytopeType ct; 51 PetscInt cStart, cEnd; 52 53 PetscFunctionBegin; 54 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 55 if (cEnd <= cStart) { 56 *simplex = PETSC_FALSE; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 60 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@ 65 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 66 67 Input Parameters: 68 + dm - The `DMPLEX` object 69 - height - The cell height in the Plex, 0 is the default 70 71 Output Parameters: 72 + cStart - The first "normal" cell 73 - cEnd - The upper bound on "normal" cells 74 75 Level: developer 76 77 Note: 78 This function requires that tensor cells are ordered last. 79 80 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 81 @*/ 82 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 83 { 84 DMLabel ctLabel; 85 IS valueIS; 86 const PetscInt *ctypes; 87 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 88 89 PetscFunctionBegin; 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 92 PetscCall(ISGetLocalSize(valueIS, &Nct)); 93 PetscCall(ISGetIndices(valueIS, &ctypes)); 94 if (!Nct) cS = cE = 0; 95 for (PetscInt t = 0; t < Nct; ++t) { 96 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 97 PetscInt ctS, ctE, ht; 98 99 if (ct == DM_POLYTOPE_UNKNOWN) { 100 // If any cells are not typed, just use all cells 101 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 102 break; 103 } 104 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 105 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 106 if (ctS >= ctE) continue; 107 // Check that a point has the right height 108 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 109 if (ht != height) continue; 110 cS = PetscMin(cS, ctS); 111 cE = PetscMax(cE, ctE); 112 } 113 PetscCall(ISDestroy(&valueIS)); 114 // Reset label for fast lookup 115 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 116 if (cStart) *cStart = cS; 117 if (cEnd) *cEnd = cE; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 122 { 123 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 124 PetscInt *sStart, *sEnd; 125 PetscViewerVTKFieldType *ft; 126 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 127 DMLabel depthLabel, ctLabel; 128 129 PetscFunctionBegin; 130 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 162 } 163 164 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 165 *types = 0; 166 167 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 168 if (globalvcdof[c]) ++(*types); 169 } 170 171 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 172 t = 0; 173 if (globalvcdof[DM_NUM_POLYTOPES]) { 174 sStart[t] = vStart; 175 sEnd[t] = vEnd; 176 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 177 ++t; 178 } 179 180 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 181 if (globalvcdof[c]) { 182 const DMPolytopeType ict = (DMPolytopeType)c; 183 184 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 185 sStart[t] = cStart; 186 sEnd[t] = cEnd; 187 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 188 ++t; 189 } 190 } 191 192 if (!(*types)) { 193 if (field >= 0) { 194 const char *fieldname; 195 196 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 197 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 198 } else { 199 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 200 } 201 } 202 203 *ssStart = sStart; 204 *ssEnd = sEnd; 205 *sft = ft; 206 PetscFunctionReturn(PETSC_SUCCESS); 207 } 208 209 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 210 { 211 PetscFunctionBegin; 212 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 213 PetscFunctionReturn(PETSC_SUCCESS); 214 } 215 216 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 217 { 218 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 219 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 220 221 PetscFunctionBegin; 222 *ft = PETSC_VTK_INVALID; 223 PetscCall(DMGetCoordinateDim(dm, &cdim)); 224 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 225 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 226 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 227 if (field >= 0) { 228 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 229 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 230 } else { 231 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 232 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 233 } 234 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 235 if (globalvcdof[0]) { 236 *sStart = vStart; 237 *sEnd = vEnd; 238 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 239 else *ft = PETSC_VTK_POINT_FIELD; 240 } else if (globalvcdof[1]) { 241 *sStart = cStart; 242 *sEnd = cEnd; 243 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 244 else *ft = PETSC_VTK_CELL_FIELD; 245 } else { 246 if (field >= 0) { 247 const char *fieldname; 248 249 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 250 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 251 } else { 252 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 253 } 254 } 255 PetscFunctionReturn(PETSC_SUCCESS); 256 } 257 258 /*@ 259 DMPlexVecView1D - Plot many 1D solutions on the same line graph 260 261 Collective 262 263 Input Parameters: 264 + dm - The `DMPLEX` object 265 . n - The number of vectors 266 . u - The array of local vectors 267 - viewer - The `PetscViewer` 268 269 Level: advanced 270 271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 272 @*/ 273 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 274 { 275 PetscDS ds; 276 PetscDraw draw = NULL; 277 PetscDrawLG lg; 278 Vec coordinates; 279 const PetscScalar *coords, **sol; 280 PetscReal *vals; 281 PetscInt *Nc; 282 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 283 char **names; 284 285 PetscFunctionBegin; 286 PetscCall(DMGetDS(dm, &ds)); 287 PetscCall(PetscDSGetNumFields(ds, &Nf)); 288 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 289 PetscCall(PetscDSGetComponents(ds, &Nc)); 290 291 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 292 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 293 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 294 295 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 296 for (i = 0, l = 0; i < n; ++i) { 297 const char *vname; 298 299 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 300 for (f = 0; f < Nf; ++f) { 301 PetscObject disc; 302 const char *fname; 303 char tmpname[PETSC_MAX_PATH_LEN]; 304 305 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 306 /* TODO Create names for components */ 307 for (c = 0; c < Nc[f]; ++c, ++l) { 308 PetscCall(PetscObjectGetName(disc, &fname)); 309 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 312 PetscCall(PetscStrallocpy(tmpname, &names[l])); 313 } 314 } 315 } 316 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 317 /* Just add P_1 support for now */ 318 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 319 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 320 PetscCall(VecGetArrayRead(coordinates, &coords)); 321 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 322 for (v = vStart; v < vEnd; ++v) { 323 PetscScalar *x, *svals; 324 325 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 326 for (i = 0; i < n; ++i) { 327 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 328 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 329 } 330 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 331 } 332 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 333 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 334 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 335 PetscCall(PetscFree3(sol, names, vals)); 336 337 PetscCall(PetscDrawLGDraw(lg)); 338 PetscCall(PetscDrawLGDestroy(&lg)); 339 PetscFunctionReturn(PETSC_SUCCESS); 340 } 341 342 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 343 { 344 DM dm; 345 346 PetscFunctionBegin; 347 PetscCall(VecGetDM(u, &dm)); 348 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 349 PetscFunctionReturn(PETSC_SUCCESS); 350 } 351 352 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 353 { 354 DM dm; 355 PetscSection s; 356 PetscDraw draw, popup; 357 DM cdm; 358 PetscSection coordSection; 359 Vec coordinates; 360 const PetscScalar *array; 361 PetscReal lbound[3], ubound[3]; 362 PetscReal vbound[2], time; 363 PetscBool flg; 364 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 365 const char *name; 366 char title[PETSC_MAX_PATH_LEN]; 367 368 PetscFunctionBegin; 369 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 370 PetscCall(VecGetDM(v, &dm)); 371 PetscCall(DMGetCoordinateDim(dm, &dim)); 372 PetscCall(DMGetLocalSection(dm, &s)); 373 PetscCall(PetscSectionGetNumFields(s, &Nf)); 374 PetscCall(DMGetCoarsenLevel(dm, &level)); 375 PetscCall(DMGetCoordinateDM(dm, &cdm)); 376 PetscCall(DMGetLocalSection(cdm, &coordSection)); 377 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 378 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 379 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 380 381 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 382 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 383 384 PetscCall(VecGetLocalSize(coordinates, &N)); 385 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 386 PetscCall(PetscDrawClear(draw)); 387 388 /* Could implement something like DMDASelectFields() */ 389 for (f = 0; f < Nf; ++f) { 390 DM fdm = dm; 391 Vec fv = v; 392 IS fis; 393 char prefix[PETSC_MAX_PATH_LEN]; 394 const char *fname; 395 396 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 397 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 398 399 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 400 else prefix[0] = '\0'; 401 if (Nf > 1) { 402 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 403 PetscCall(VecGetSubVector(v, fis, &fv)); 404 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 405 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 406 } 407 for (comp = 0; comp < Nc; ++comp, ++w) { 408 PetscInt nmax = 2; 409 410 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 411 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 412 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 413 PetscCall(PetscDrawSetTitle(draw, title)); 414 415 /* TODO Get max and min only for this component */ 416 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 417 if (!flg) { 418 PetscCall(VecMin(fv, NULL, &vbound[0])); 419 PetscCall(VecMax(fv, NULL, &vbound[1])); 420 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 421 } 422 423 PetscCall(PetscDrawGetPopup(draw, &popup)); 424 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 425 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 426 PetscCall(VecGetArrayRead(fv, &array)); 427 for (c = cStart; c < cEnd; ++c) { 428 PetscScalar *coords = NULL, *a = NULL; 429 const PetscScalar *coords_arr; 430 PetscBool isDG; 431 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 432 433 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 434 if (a) { 435 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 436 color[1] = color[2] = color[3] = color[0]; 437 } else { 438 PetscScalar *vals = NULL; 439 PetscInt numVals, va; 440 441 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 442 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 443 switch (numVals / Nc) { 444 case 3: /* P1 Triangle */ 445 case 4: /* P1 Quadrangle */ 446 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 447 break; 448 case 6: /* P2 Triangle */ 449 case 8: /* P2 Quadrangle */ 450 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 451 break; 452 default: 453 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 454 } 455 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 456 } 457 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 458 switch (numCoords) { 459 case 6: 460 case 12: /* Localized triangle */ 461 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 462 break; 463 case 8: 464 case 16: /* Localized quadrilateral */ 465 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 466 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 467 break; 468 default: 469 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 470 } 471 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 472 } 473 PetscCall(VecRestoreArrayRead(fv, &array)); 474 PetscCall(PetscDrawFlush(draw)); 475 PetscCall(PetscDrawPause(draw)); 476 PetscCall(PetscDrawSave(draw)); 477 } 478 if (Nf > 1) { 479 PetscCall(VecRestoreSubVector(v, fis, &fv)); 480 PetscCall(ISDestroy(&fis)); 481 PetscCall(DMDestroy(&fdm)); 482 } 483 } 484 PetscFunctionReturn(PETSC_SUCCESS); 485 } 486 487 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 488 { 489 DM dm; 490 PetscDraw draw; 491 PetscInt dim; 492 PetscBool isnull; 493 494 PetscFunctionBegin; 495 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 496 PetscCall(PetscDrawIsNull(draw, &isnull)); 497 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 498 499 PetscCall(VecGetDM(v, &dm)); 500 PetscCall(DMGetCoordinateDim(dm, &dim)); 501 switch (dim) { 502 case 1: 503 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 504 break; 505 case 2: 506 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 507 break; 508 default: 509 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 510 } 511 PetscFunctionReturn(PETSC_SUCCESS); 512 } 513 514 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 515 { 516 DM dm; 517 Vec locv; 518 const char *name; 519 PetscSection section; 520 PetscInt pStart, pEnd; 521 PetscInt numFields; 522 PetscViewerVTKFieldType ft; 523 524 PetscFunctionBegin; 525 PetscCall(VecGetDM(v, &dm)); 526 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 527 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 528 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 529 PetscCall(VecCopy(v, locv)); 530 PetscCall(DMGetLocalSection(dm, §ion)); 531 PetscCall(PetscSectionGetNumFields(section, &numFields)); 532 if (!numFields) { 533 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 534 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 535 } else { 536 PetscInt f; 537 538 for (f = 0; f < numFields; f++) { 539 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 540 if (ft == PETSC_VTK_INVALID) continue; 541 PetscCall(PetscObjectReference((PetscObject)locv)); 542 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 543 } 544 PetscCall(VecDestroy(&locv)); 545 } 546 PetscFunctionReturn(PETSC_SUCCESS); 547 } 548 549 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 550 { 551 DM dm; 552 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 553 554 PetscFunctionBegin; 555 PetscCall(VecGetDM(v, &dm)); 556 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 562 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 563 PetscInt i, numFields; 564 PetscObject fe; 565 PetscBool fem = PETSC_FALSE; 566 Vec locv = v; 567 const char *name; 568 PetscInt step; 569 PetscReal time; 570 571 PetscCall(DMGetNumFields(dm, &numFields)); 572 for (i = 0; i < numFields; i++) { 573 PetscCall(DMGetField(dm, i, NULL, &fe)); 574 if (fe->classid == PETSCFE_CLASSID) { 575 fem = PETSC_TRUE; 576 break; 577 } 578 } 579 if (fem) { 580 PetscObject isZero; 581 582 PetscCall(DMGetLocalVector(dm, &locv)); 583 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 584 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 585 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 586 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 587 PetscCall(VecCopy(v, locv)); 588 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 589 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 590 } 591 if (isvtk) { 592 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 593 } else if (ishdf5) { 594 #if defined(PETSC_HAVE_HDF5) 595 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 596 #else 597 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 598 #endif 599 } else if (isdraw) { 600 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 601 } else if (isglvis) { 602 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 603 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 604 PetscCall(VecView_GLVis(locv, viewer)); 605 } else if (iscgns) { 606 #if defined(PETSC_HAVE_CGNS) 607 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 608 #else 609 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 610 #endif 611 } 612 if (fem) { 613 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 614 PetscCall(DMRestoreLocalVector(dm, &locv)); 615 } 616 } else { 617 PetscBool isseq; 618 619 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 620 if (isseq) PetscCall(VecView_Seq(v, viewer)); 621 else PetscCall(VecView_MPI(v, viewer)); 622 } 623 PetscFunctionReturn(PETSC_SUCCESS); 624 } 625 626 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 627 { 628 DM dm; 629 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 630 631 PetscFunctionBegin; 632 PetscCall(VecGetDM(v, &dm)); 633 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (isvtk || isdraw || isglvis || iscgns) { 641 Vec locv; 642 PetscObject isZero; 643 const char *name; 644 645 PetscCall(DMGetLocalVector(dm, &locv)); 646 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 647 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 648 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 649 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 650 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 651 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 652 PetscCall(VecView_Plex_Local(locv, viewer)); 653 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 654 PetscCall(DMRestoreLocalVector(dm, &locv)); 655 } else if (ishdf5) { 656 #if defined(PETSC_HAVE_HDF5) 657 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 658 #else 659 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 660 #endif 661 } else if (isexodusii) { 662 #if defined(PETSC_HAVE_EXODUSII) 663 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 664 #else 665 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 666 #endif 667 } else { 668 PetscBool isseq; 669 670 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 671 if (isseq) PetscCall(VecView_Seq(v, viewer)); 672 else PetscCall(VecView_MPI(v, viewer)); 673 } 674 PetscFunctionReturn(PETSC_SUCCESS); 675 } 676 677 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 678 { 679 DM dm; 680 MPI_Comm comm; 681 PetscViewerFormat format; 682 Vec v; 683 PetscBool isvtk, ishdf5; 684 685 PetscFunctionBegin; 686 PetscCall(VecGetDM(originalv, &dm)); 687 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 688 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 689 PetscCall(PetscViewerGetFormat(viewer, &format)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 692 if (format == PETSC_VIEWER_NATIVE) { 693 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 694 /* this need a better fix */ 695 if (dm->useNatural) { 696 if (dm->sfNatural) { 697 const char *vecname; 698 PetscInt n, nroots; 699 700 PetscCall(VecGetLocalSize(originalv, &n)); 701 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 702 if (n == nroots) { 703 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 704 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 705 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 706 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 707 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 709 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 710 } else v = originalv; 711 } else v = originalv; 712 713 if (ishdf5) { 714 #if defined(PETSC_HAVE_HDF5) 715 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 716 #else 717 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 718 #endif 719 } else if (isvtk) { 720 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 721 } else { 722 PetscBool isseq; 723 724 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 725 if (isseq) PetscCall(VecView_Seq(v, viewer)); 726 else PetscCall(VecView_MPI(v, viewer)); 727 } 728 if (v != originalv) PetscCall(VecDestroy(&v)); 729 PetscFunctionReturn(PETSC_SUCCESS); 730 } 731 732 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 733 { 734 DM dm; 735 PetscBool ishdf5; 736 737 PetscFunctionBegin; 738 PetscCall(VecGetDM(v, &dm)); 739 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 740 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 741 if (ishdf5) { 742 DM dmBC; 743 Vec gv; 744 const char *name; 745 746 PetscCall(DMGetOutputDM(dm, &dmBC)); 747 PetscCall(DMGetGlobalVector(dmBC, &gv)); 748 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 749 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 750 PetscCall(VecLoad_Default(gv, viewer)); 751 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 753 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 754 } else PetscCall(VecLoad_Default(v, viewer)); 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 759 { 760 DM dm; 761 PetscBool ishdf5, isexodusii; 762 763 PetscFunctionBegin; 764 PetscCall(VecGetDM(v, &dm)); 765 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 768 if (ishdf5) { 769 #if defined(PETSC_HAVE_HDF5) 770 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 771 #else 772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 773 #endif 774 } else if (isexodusii) { 775 #if defined(PETSC_HAVE_EXODUSII) 776 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 777 #else 778 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 779 #endif 780 } else PetscCall(VecLoad_Default(v, viewer)); 781 PetscFunctionReturn(PETSC_SUCCESS); 782 } 783 784 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 785 { 786 DM dm; 787 PetscViewerFormat format; 788 PetscBool ishdf5; 789 790 PetscFunctionBegin; 791 PetscCall(VecGetDM(originalv, &dm)); 792 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 793 PetscCall(PetscViewerGetFormat(viewer, &format)); 794 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 795 if (format == PETSC_VIEWER_NATIVE) { 796 if (dm->useNatural) { 797 if (dm->sfNatural) { 798 if (ishdf5) { 799 #if defined(PETSC_HAVE_HDF5) 800 Vec v; 801 const char *vecname; 802 803 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 804 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 805 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 806 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 807 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 808 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 809 PetscCall(VecDestroy(&v)); 810 #else 811 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 812 #endif 813 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 814 } 815 } else PetscCall(VecLoad_Default(originalv, viewer)); 816 } 817 PetscFunctionReturn(PETSC_SUCCESS); 818 } 819 820 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 821 { 822 PetscSection coordSection; 823 Vec coordinates; 824 DMLabel depthLabel, celltypeLabel; 825 const char *name[4]; 826 const PetscScalar *a; 827 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 828 829 PetscFunctionBegin; 830 PetscCall(DMGetDimension(dm, &dim)); 831 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 832 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 833 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 834 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 835 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 836 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 837 PetscCall(VecGetArrayRead(coordinates, &a)); 838 name[0] = "vertex"; 839 name[1] = "edge"; 840 name[dim - 1] = "face"; 841 name[dim] = "cell"; 842 for (c = cStart; c < cEnd; ++c) { 843 PetscInt *closure = NULL; 844 PetscInt closureSize, cl, ct; 845 846 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 847 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 848 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 849 PetscCall(PetscViewerASCIIPushTab(viewer)); 850 for (cl = 0; cl < closureSize * 2; cl += 2) { 851 PetscInt point = closure[cl], depth, dof, off, d, p; 852 853 if ((point < pStart) || (point >= pEnd)) continue; 854 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 855 if (!dof) continue; 856 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 857 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 859 for (p = 0; p < dof / dim; ++p) { 860 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 861 for (d = 0; d < dim; ++d) { 862 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 863 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 864 } 865 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 866 } 867 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 868 } 869 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 870 PetscCall(PetscViewerASCIIPopTab(viewer)); 871 } 872 PetscCall(VecRestoreArrayRead(coordinates, &a)); 873 PetscFunctionReturn(PETSC_SUCCESS); 874 } 875 876 typedef enum { 877 CS_CARTESIAN, 878 CS_POLAR, 879 CS_CYLINDRICAL, 880 CS_SPHERICAL 881 } CoordSystem; 882 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 883 884 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 885 { 886 PetscInt i; 887 888 PetscFunctionBegin; 889 if (dim > 3) { 890 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 891 } else { 892 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 893 894 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 895 switch (cs) { 896 case CS_CARTESIAN: 897 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 898 break; 899 case CS_POLAR: 900 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 901 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 902 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 903 break; 904 case CS_CYLINDRICAL: 905 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 906 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 907 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 908 trcoords[2] = coords[2]; 909 break; 910 case CS_SPHERICAL: 911 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 912 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 913 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 914 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 915 break; 916 } 917 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 918 } 919 PetscFunctionReturn(PETSC_SUCCESS); 920 } 921 922 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 923 { 924 DM_Plex *mesh = (DM_Plex *)dm->data; 925 DM cdm, cdmCell; 926 PetscSection coordSection, coordSectionCell; 927 Vec coordinates, coordinatesCell; 928 PetscViewerFormat format; 929 930 PetscFunctionBegin; 931 PetscCall(PetscViewerGetFormat(viewer, &format)); 932 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 933 const char *name; 934 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 935 PetscInt pStart, pEnd, p, numLabels, l; 936 PetscMPIInt rank, size; 937 938 PetscCall(DMGetCoordinateDM(dm, &cdm)); 939 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 940 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 941 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 942 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 943 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 944 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 945 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 946 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 947 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 949 PetscCall(DMGetDimension(dm, &dim)); 950 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 951 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 952 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 953 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 955 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 956 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 957 for (p = pStart; p < pEnd; ++p) { 958 PetscInt dof, off, s; 959 960 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 961 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 962 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 963 } 964 PetscCall(PetscViewerFlush(viewer)); 965 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 966 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 967 for (p = pStart; p < pEnd; ++p) { 968 PetscInt dof, off, c; 969 970 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 971 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 972 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 973 } 974 PetscCall(PetscViewerFlush(viewer)); 975 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 976 if (coordSection && coordinates) { 977 CoordSystem cs = CS_CARTESIAN; 978 const PetscScalar *array, *arrayCell = NULL; 979 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 980 PetscMPIInt rank; 981 const char *name; 982 983 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 984 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 985 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 986 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 987 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 988 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 989 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 990 pStart = PetscMin(pvStart, pcStart); 991 pEnd = PetscMax(pvEnd, pcEnd); 992 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 994 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 995 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 996 997 PetscCall(VecGetArrayRead(coordinates, &array)); 998 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 999 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1000 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1001 for (p = pStart; p < pEnd; ++p) { 1002 PetscInt dof, off; 1003 1004 if (p >= pvStart && p < pvEnd) { 1005 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1006 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1007 if (dof) { 1008 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1009 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1010 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1011 } 1012 } 1013 if (cdmCell && p >= pcStart && p < pcEnd) { 1014 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1015 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1016 if (dof) { 1017 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1018 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1019 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1020 } 1021 } 1022 } 1023 PetscCall(PetscViewerFlush(viewer)); 1024 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1025 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1026 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1027 } 1028 PetscCall(DMGetNumLabels(dm, &numLabels)); 1029 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1030 for (l = 0; l < numLabels; ++l) { 1031 DMLabel label; 1032 PetscBool isdepth; 1033 const char *name; 1034 1035 PetscCall(DMGetLabelName(dm, l, &name)); 1036 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1037 if (isdepth) continue; 1038 PetscCall(DMGetLabel(dm, name, &label)); 1039 PetscCall(DMLabelView(label, viewer)); 1040 } 1041 if (size > 1) { 1042 PetscSF sf; 1043 1044 PetscCall(DMGetPointSF(dm, &sf)); 1045 PetscCall(PetscSFView(sf, viewer)); 1046 } 1047 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 1048 PetscCall(PetscViewerFlush(viewer)); 1049 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1050 const char *name, *color; 1051 const char *defcolors[3] = {"gray", "orange", "green"}; 1052 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1053 char lname[PETSC_MAX_PATH_LEN]; 1054 PetscReal scale = 2.0; 1055 PetscReal tikzscale = 1.0; 1056 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1057 double tcoords[3]; 1058 PetscScalar *coords; 1059 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 1060 PetscMPIInt rank, size; 1061 char **names, **colors, **lcolors; 1062 PetscBool flg, lflg; 1063 PetscBT wp = NULL; 1064 PetscInt pEnd, pStart; 1065 1066 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1069 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1070 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1071 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1072 PetscCall(DMGetDimension(dm, &dim)); 1073 PetscCall(DMPlexGetDepth(dm, &depth)); 1074 PetscCall(DMGetNumLabels(dm, &numLabels)); 1075 numLabels = PetscMax(numLabels, 10); 1076 numColors = 10; 1077 numLColors = 10; 1078 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1080 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1081 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1082 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1083 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1084 n = 4; 1085 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1086 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1087 n = 4; 1088 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1089 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1090 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1091 if (!useLabels) numLabels = 0; 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1093 if (!useColors) { 1094 numColors = 3; 1095 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1096 } 1097 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1098 if (!useColors) { 1099 numLColors = 4; 1100 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1101 } 1102 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1103 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1104 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1105 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1106 if (depth < dim) plotEdges = PETSC_FALSE; 1107 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1108 1109 /* filter points with labelvalue != labeldefaultvalue */ 1110 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1112 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1113 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1114 if (lflg) { 1115 DMLabel lbl; 1116 1117 PetscCall(DMGetLabel(dm, lname, &lbl)); 1118 if (lbl) { 1119 PetscInt val, defval; 1120 1121 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1122 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1123 for (c = pStart; c < pEnd; c++) { 1124 PetscInt *closure = NULL; 1125 PetscInt closureSize; 1126 1127 PetscCall(DMLabelGetValue(lbl, c, &val)); 1128 if (val == defval) continue; 1129 1130 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1131 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1132 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1133 } 1134 } 1135 } 1136 1137 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1138 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1139 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1140 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1141 \\documentclass[tikz]{standalone}\n\n\ 1142 \\usepackage{pgflibraryshapes}\n\ 1143 \\usetikzlibrary{backgrounds}\n\ 1144 \\usetikzlibrary{arrows}\n\ 1145 \\begin{document}\n")); 1146 if (size > 1) { 1147 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1148 for (p = 0; p < size; ++p) { 1149 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1150 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1151 } 1152 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1153 } 1154 if (drawHasse) { 1155 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1156 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1169 } 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1171 1172 /* Plot vertices */ 1173 PetscCall(VecGetArray(coordinates, &coords)); 1174 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1175 for (v = vStart; v < vEnd; ++v) { 1176 PetscInt off, dof, d; 1177 PetscBool isLabeled = PETSC_FALSE; 1178 1179 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1180 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1181 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1182 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1183 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1184 for (d = 0; d < dof; ++d) { 1185 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1186 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1187 } 1188 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1189 if (dim == 3) { 1190 PetscReal tmp = tcoords[1]; 1191 tcoords[1] = tcoords[2]; 1192 tcoords[2] = -tmp; 1193 } 1194 for (d = 0; d < dof; ++d) { 1195 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1196 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1197 } 1198 if (drawHasse) color = colors[0 % numColors]; 1199 else color = colors[rank % numColors]; 1200 for (l = 0; l < numLabels; ++l) { 1201 PetscInt val; 1202 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1203 if (val >= 0) { 1204 color = lcolors[l % numLColors]; 1205 isLabeled = PETSC_TRUE; 1206 break; 1207 } 1208 } 1209 if (drawNumbers[0]) { 1210 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1211 } else if (drawColors[0]) { 1212 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1213 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1214 } 1215 PetscCall(VecRestoreArray(coordinates, &coords)); 1216 PetscCall(PetscViewerFlush(viewer)); 1217 /* Plot edges */ 1218 if (plotEdges) { 1219 PetscCall(VecGetArray(coordinates, &coords)); 1220 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1221 for (e = eStart; e < eEnd; ++e) { 1222 const PetscInt *cone; 1223 PetscInt coneSize, offA, offB, dof, d; 1224 1225 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1226 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1227 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1228 PetscCall(DMPlexGetCone(dm, e, &cone)); 1229 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1230 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1231 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1232 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1233 for (d = 0; d < dof; ++d) { 1234 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1235 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1236 } 1237 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1238 if (dim == 3) { 1239 PetscReal tmp = tcoords[1]; 1240 tcoords[1] = tcoords[2]; 1241 tcoords[2] = -tmp; 1242 } 1243 for (d = 0; d < dof; ++d) { 1244 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1245 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1246 } 1247 if (drawHasse) color = colors[1 % numColors]; 1248 else color = colors[rank % numColors]; 1249 for (l = 0; l < numLabels; ++l) { 1250 PetscInt val; 1251 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1252 if (val >= 0) { 1253 color = lcolors[l % numLColors]; 1254 break; 1255 } 1256 } 1257 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1258 } 1259 PetscCall(VecRestoreArray(coordinates, &coords)); 1260 PetscCall(PetscViewerFlush(viewer)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1262 } 1263 /* Plot cells */ 1264 if (dim == 3 || !drawNumbers[1]) { 1265 for (e = eStart; e < eEnd; ++e) { 1266 const PetscInt *cone; 1267 1268 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1269 color = colors[rank % numColors]; 1270 for (l = 0; l < numLabels; ++l) { 1271 PetscInt val; 1272 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1273 if (val >= 0) { 1274 color = lcolors[l % numLColors]; 1275 break; 1276 } 1277 } 1278 PetscCall(DMPlexGetCone(dm, e, &cone)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1280 } 1281 } else { 1282 DMPolytopeType ct; 1283 1284 /* Drawing a 2D polygon */ 1285 for (c = cStart; c < cEnd; ++c) { 1286 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1287 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1288 if (DMPolytopeTypeIsHybrid(ct)) { 1289 const PetscInt *cone; 1290 PetscInt coneSize, e; 1291 1292 PetscCall(DMPlexGetCone(dm, c, &cone)); 1293 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1294 for (e = 0; e < coneSize; ++e) { 1295 const PetscInt *econe; 1296 1297 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1298 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1299 } 1300 } else { 1301 PetscInt *closure = NULL; 1302 PetscInt closureSize, Nv = 0, v; 1303 1304 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1305 for (p = 0; p < closureSize * 2; p += 2) { 1306 const PetscInt point = closure[p]; 1307 1308 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1309 } 1310 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1311 for (v = 0; v <= Nv; ++v) { 1312 const PetscInt vertex = closure[v % Nv]; 1313 1314 if (v > 0) { 1315 if (plotEdges) { 1316 const PetscInt *edge; 1317 PetscInt endpoints[2], ne; 1318 1319 endpoints[0] = closure[v - 1]; 1320 endpoints[1] = vertex; 1321 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1322 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1323 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1324 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1325 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1326 } 1327 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1328 } 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1330 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1331 } 1332 } 1333 } 1334 for (c = cStart; c < cEnd; ++c) { 1335 double ccoords[3] = {0.0, 0.0, 0.0}; 1336 PetscBool isLabeled = PETSC_FALSE; 1337 PetscScalar *cellCoords = NULL; 1338 const PetscScalar *array; 1339 PetscInt numCoords, cdim, d; 1340 PetscBool isDG; 1341 1342 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1343 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1344 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1345 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1346 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1347 for (p = 0; p < numCoords / cdim; ++p) { 1348 for (d = 0; d < cdim; ++d) { 1349 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1350 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1351 } 1352 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1353 if (cdim == 3) { 1354 PetscReal tmp = tcoords[1]; 1355 tcoords[1] = tcoords[2]; 1356 tcoords[2] = -tmp; 1357 } 1358 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1359 } 1360 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1361 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1362 for (d = 0; d < cdim; ++d) { 1363 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1364 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1365 } 1366 if (drawHasse) color = colors[depth % numColors]; 1367 else color = colors[rank % numColors]; 1368 for (l = 0; l < numLabels; ++l) { 1369 PetscInt val; 1370 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1371 if (val >= 0) { 1372 color = lcolors[l % numLColors]; 1373 isLabeled = PETSC_TRUE; 1374 break; 1375 } 1376 } 1377 if (drawNumbers[dim]) { 1378 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1379 } else if (drawColors[dim]) { 1380 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1381 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1382 } 1383 if (drawHasse) { 1384 color = colors[depth % numColors]; 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1388 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1389 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1390 1391 color = colors[1 % numColors]; 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1397 1398 color = colors[0 % numColors]; 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1404 1405 for (p = pStart; p < pEnd; ++p) { 1406 const PetscInt *cone; 1407 PetscInt coneSize, cp; 1408 1409 PetscCall(DMPlexGetCone(dm, p, &cone)); 1410 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1411 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1412 } 1413 } 1414 PetscCall(PetscViewerFlush(viewer)); 1415 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1418 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1419 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1420 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1421 PetscCall(PetscFree3(names, colors, lcolors)); 1422 PetscCall(PetscBTDestroy(&wp)); 1423 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1424 Vec cown, acown; 1425 VecScatter sct; 1426 ISLocalToGlobalMapping g2l; 1427 IS gid, acis; 1428 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1429 MPI_Group ggroup, ngroup; 1430 PetscScalar *array, nid; 1431 const PetscInt *idxs; 1432 PetscInt *idxs2, *start, *adjacency, *work; 1433 PetscInt64 lm[3], gm[3]; 1434 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1435 PetscMPIInt d1, d2, rank; 1436 1437 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1438 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1439 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1440 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1441 #endif 1442 if (ncomm != MPI_COMM_NULL) { 1443 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1444 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1445 d1 = 0; 1446 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1447 nid = d2; 1448 PetscCallMPI(MPI_Group_free(&ggroup)); 1449 PetscCallMPI(MPI_Group_free(&ngroup)); 1450 PetscCallMPI(MPI_Comm_free(&ncomm)); 1451 } else nid = 0.0; 1452 1453 /* Get connectivity */ 1454 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1455 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1456 1457 /* filter overlapped local cells */ 1458 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1459 PetscCall(ISGetIndices(gid, &idxs)); 1460 PetscCall(ISGetLocalSize(gid, &cum)); 1461 PetscCall(PetscMalloc1(cum, &idxs2)); 1462 for (c = cStart, cum = 0; c < cEnd; c++) { 1463 if (idxs[c - cStart] < 0) continue; 1464 idxs2[cum++] = idxs[c - cStart]; 1465 } 1466 PetscCall(ISRestoreIndices(gid, &idxs)); 1467 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1468 PetscCall(ISDestroy(&gid)); 1469 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1470 1471 /* support for node-aware cell locality */ 1472 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1473 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1474 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1475 PetscCall(VecGetArray(cown, &array)); 1476 for (c = 0; c < numVertices; c++) array[c] = nid; 1477 PetscCall(VecRestoreArray(cown, &array)); 1478 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1479 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1480 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1481 PetscCall(ISDestroy(&acis)); 1482 PetscCall(VecScatterDestroy(&sct)); 1483 PetscCall(VecDestroy(&cown)); 1484 1485 /* compute edgeCut */ 1486 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1487 PetscCall(PetscMalloc1(cum, &work)); 1488 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1489 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1490 PetscCall(ISDestroy(&gid)); 1491 PetscCall(VecGetArray(acown, &array)); 1492 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1493 PetscInt totl; 1494 1495 totl = start[c + 1] - start[c]; 1496 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1497 for (i = 0; i < totl; i++) { 1498 if (work[i] < 0) { 1499 ect += 1; 1500 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1501 } 1502 } 1503 } 1504 PetscCall(PetscFree(work)); 1505 PetscCall(VecRestoreArray(acown, &array)); 1506 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1507 lm[1] = -numVertices; 1508 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1510 lm[0] = ect; /* edgeCut */ 1511 lm[1] = ectn; /* node-aware edgeCut */ 1512 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1513 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1514 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1515 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1516 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1517 #else 1518 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1519 #endif 1520 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1521 PetscCall(PetscFree(start)); 1522 PetscCall(PetscFree(adjacency)); 1523 PetscCall(VecDestroy(&acown)); 1524 } else { 1525 const char *name; 1526 PetscInt *sizes, *hybsizes, *ghostsizes; 1527 PetscInt locDepth, depth, cellHeight, dim, d; 1528 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1529 PetscInt numLabels, l, maxSize = 17; 1530 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1531 MPI_Comm comm; 1532 PetscMPIInt size, rank; 1533 1534 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1535 PetscCallMPI(MPI_Comm_size(comm, &size)); 1536 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1537 PetscCall(DMGetDimension(dm, &dim)); 1538 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1539 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1540 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1541 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1542 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1543 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1544 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1545 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1546 gcNum = gcEnd - gcStart; 1547 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1548 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1549 for (d = 0; d <= depth; d++) { 1550 PetscInt Nc[2] = {0, 0}, ict; 1551 1552 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1553 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1554 ict = ct0; 1555 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1556 ct0 = (DMPolytopeType)ict; 1557 for (p = pStart; p < pEnd; ++p) { 1558 DMPolytopeType ct; 1559 1560 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1561 if (ct == ct0) ++Nc[0]; 1562 else ++Nc[1]; 1563 } 1564 if (size < maxSize) { 1565 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1566 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1567 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1568 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1569 for (p = 0; p < size; ++p) { 1570 if (rank == 0) { 1571 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1572 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1573 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1574 } 1575 } 1576 } else { 1577 PetscInt locMinMax[2]; 1578 1579 locMinMax[0] = Nc[0] + Nc[1]; 1580 locMinMax[1] = Nc[0] + Nc[1]; 1581 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1582 locMinMax[0] = Nc[1]; 1583 locMinMax[1] = Nc[1]; 1584 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1585 if (d == depth) { 1586 locMinMax[0] = gcNum; 1587 locMinMax[1] = gcNum; 1588 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1589 } 1590 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1591 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1592 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1593 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1594 } 1595 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1596 } 1597 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1598 { 1599 const PetscReal *maxCell; 1600 const PetscReal *L; 1601 PetscBool localized; 1602 1603 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1604 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1605 if (L || localized) { 1606 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1607 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1608 if (L) { 1609 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1610 for (d = 0; d < dim; ++d) { 1611 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1612 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1613 } 1614 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1615 } 1616 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1617 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1618 } 1619 } 1620 PetscCall(DMGetNumLabels(dm, &numLabels)); 1621 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1622 for (l = 0; l < numLabels; ++l) { 1623 DMLabel label; 1624 const char *name; 1625 IS valueIS; 1626 const PetscInt *values; 1627 PetscInt numValues, v; 1628 1629 PetscCall(DMGetLabelName(dm, l, &name)); 1630 PetscCall(DMGetLabel(dm, name, &label)); 1631 PetscCall(DMLabelGetNumValues(label, &numValues)); 1632 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1633 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1634 PetscCall(ISGetIndices(valueIS, &values)); 1635 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1636 for (v = 0; v < numValues; ++v) { 1637 PetscInt size; 1638 1639 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1640 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1641 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1642 } 1643 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1644 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1645 PetscCall(ISRestoreIndices(valueIS, &values)); 1646 PetscCall(ISDestroy(&valueIS)); 1647 } 1648 { 1649 char **labelNames; 1650 PetscInt Nl = numLabels; 1651 PetscBool flg; 1652 1653 PetscCall(PetscMalloc1(Nl, &labelNames)); 1654 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1655 for (l = 0; l < Nl; ++l) { 1656 DMLabel label; 1657 1658 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1659 if (flg) { 1660 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1661 PetscCall(DMLabelView(label, viewer)); 1662 } 1663 PetscCall(PetscFree(labelNames[l])); 1664 } 1665 PetscCall(PetscFree(labelNames)); 1666 } 1667 /* If no fields are specified, people do not want to see adjacency */ 1668 if (dm->Nf) { 1669 PetscInt f; 1670 1671 for (f = 0; f < dm->Nf; ++f) { 1672 const char *name; 1673 1674 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1675 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1676 PetscCall(PetscViewerASCIIPushTab(viewer)); 1677 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1678 if (dm->fields[f].adjacency[0]) { 1679 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1680 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1681 } else { 1682 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1683 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1684 } 1685 PetscCall(PetscViewerASCIIPopTab(viewer)); 1686 } 1687 } 1688 PetscCall(DMGetCoarseDM(dm, &cdm)); 1689 if (cdm) { 1690 PetscCall(PetscViewerASCIIPushTab(viewer)); 1691 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1692 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1693 PetscCall(PetscViewerASCIIPopTab(viewer)); 1694 } 1695 } 1696 PetscFunctionReturn(PETSC_SUCCESS); 1697 } 1698 1699 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1700 { 1701 DMPolytopeType ct; 1702 PetscMPIInt rank; 1703 PetscInt cdim; 1704 1705 PetscFunctionBegin; 1706 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1707 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1708 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1709 switch (ct) { 1710 case DM_POLYTOPE_SEGMENT: 1711 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1712 switch (cdim) { 1713 case 1: { 1714 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1715 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1716 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1718 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1719 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1720 } break; 1721 case 2: { 1722 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1723 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1724 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1725 1726 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1727 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1728 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1729 } break; 1730 default: 1731 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1732 } 1733 break; 1734 case DM_POLYTOPE_TRIANGLE: 1735 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1738 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1739 break; 1740 case DM_POLYTOPE_QUADRILATERAL: 1741 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1742 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1746 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1747 break; 1748 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1749 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1750 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1754 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1755 break; 1756 case DM_POLYTOPE_FV_GHOST: 1757 break; 1758 default: 1759 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1760 } 1761 PetscFunctionReturn(PETSC_SUCCESS); 1762 } 1763 1764 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1765 { 1766 DMPolytopeType ct; 1767 PetscReal centroid[2] = {0., 0.}; 1768 PetscMPIInt rank; 1769 PetscInt fillColor, v, e, d; 1770 1771 PetscFunctionBegin; 1772 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1773 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1774 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1775 switch (ct) { 1776 case DM_POLYTOPE_TRIANGLE: { 1777 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1778 1779 for (v = 0; v < 3; ++v) { 1780 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1781 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1782 } 1783 for (e = 0; e < 3; ++e) { 1784 refCoords[0] = refVertices[e * 2 + 0]; 1785 refCoords[1] = refVertices[e * 2 + 1]; 1786 for (d = 1; d <= edgeDiv; ++d) { 1787 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1788 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1789 } 1790 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1791 for (d = 0; d < edgeDiv; ++d) { 1792 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1793 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1794 } 1795 } 1796 } break; 1797 default: 1798 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1799 } 1800 PetscFunctionReturn(PETSC_SUCCESS); 1801 } 1802 1803 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1804 { 1805 PetscDraw draw; 1806 DM cdm; 1807 PetscSection coordSection; 1808 Vec coordinates; 1809 PetscReal xyl[3], xyr[3]; 1810 PetscReal *refCoords, *edgeCoords; 1811 PetscBool isnull, drawAffine = PETSC_TRUE; 1812 PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4; 1813 1814 PetscFunctionBegin; 1815 PetscCall(DMGetCoordinateDim(dm, &dim)); 1816 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1817 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1818 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1819 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1820 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1821 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1822 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1823 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1824 1825 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1826 PetscCall(PetscDrawIsNull(draw, &isnull)); 1827 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1828 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1829 1830 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1831 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1832 PetscCall(PetscDrawClear(draw)); 1833 1834 for (c = cStart; c < cEnd; ++c) { 1835 PetscScalar *coords = NULL; 1836 const PetscScalar *coords_arr; 1837 PetscInt numCoords; 1838 PetscBool isDG; 1839 1840 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1841 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1842 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1843 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1844 } 1845 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1846 PetscCall(PetscDrawFlush(draw)); 1847 PetscCall(PetscDrawPause(draw)); 1848 PetscCall(PetscDrawSave(draw)); 1849 PetscFunctionReturn(PETSC_SUCCESS); 1850 } 1851 1852 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1853 { 1854 DM odm = dm, rdm = dm, cdm; 1855 PetscFE fe; 1856 PetscSpace sp; 1857 PetscClassId id; 1858 PetscInt degree; 1859 PetscBool hoView = PETSC_TRUE; 1860 1861 PetscFunctionBegin; 1862 PetscObjectOptionsBegin((PetscObject)dm); 1863 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1864 PetscOptionsEnd(); 1865 PetscCall(PetscObjectReference((PetscObject)dm)); 1866 *hdm = dm; 1867 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1868 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1869 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1870 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1871 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1872 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1873 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1874 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1875 DM cdm, rcdm; 1876 Mat In; 1877 Vec cl, rcl; 1878 1879 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1880 if (rd > 1) PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1881 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1882 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1883 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1884 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1885 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1886 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1887 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1888 PetscCall(MatMult(In, cl, rcl)); 1889 PetscCall(MatDestroy(&In)); 1890 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1891 PetscCall(DMDestroy(&odm)); 1892 odm = rdm; 1893 } 1894 *hdm = rdm; 1895 PetscFunctionReturn(PETSC_SUCCESS); 1896 } 1897 1898 #if defined(PETSC_HAVE_EXODUSII) 1899 #include <exodusII.h> 1900 #include <petscviewerexodusii.h> 1901 #endif 1902 1903 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1904 { 1905 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1906 char name[PETSC_MAX_PATH_LEN]; 1907 1908 PetscFunctionBegin; 1909 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1910 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1911 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1912 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1913 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1914 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1916 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1917 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1918 if (iascii) { 1919 PetscViewerFormat format; 1920 PetscCall(PetscViewerGetFormat(viewer, &format)); 1921 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1922 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1923 } else if (ishdf5) { 1924 #if defined(PETSC_HAVE_HDF5) 1925 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1926 #else 1927 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1928 #endif 1929 } else if (isvtk) { 1930 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1931 } else if (isdraw) { 1932 DM hdm; 1933 1934 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1935 PetscCall(DMPlexView_Draw(hdm, viewer)); 1936 PetscCall(DMDestroy(&hdm)); 1937 } else if (isglvis) { 1938 PetscCall(DMPlexView_GLVis(dm, viewer)); 1939 #if defined(PETSC_HAVE_EXODUSII) 1940 } else if (isexodus) { 1941 /* 1942 exodusII requires that all sets be part of exactly one cell set. 1943 If the dm does not have a "Cell Sets" label defined, we create one 1944 with ID 1, containing all cells. 1945 Note that if the Cell Sets label is defined but does not cover all cells, 1946 we may still have a problem. This should probably be checked here or in the viewer; 1947 */ 1948 PetscInt numCS; 1949 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1950 if (!numCS) { 1951 PetscInt cStart, cEnd, c; 1952 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1953 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1954 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1955 } 1956 PetscCall(DMView_PlexExodusII(dm, viewer)); 1957 #endif 1958 #if defined(PETSC_HAVE_CGNS) 1959 } else if (iscgns) { 1960 PetscCall(DMView_PlexCGNS(dm, viewer)); 1961 #endif 1962 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1963 /* Optionally view the partition */ 1964 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1965 if (flg) { 1966 Vec ranks; 1967 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1968 PetscCall(VecView(ranks, viewer)); 1969 PetscCall(VecDestroy(&ranks)); 1970 } 1971 /* Optionally view a label */ 1972 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1973 if (flg) { 1974 DMLabel label; 1975 Vec val; 1976 1977 PetscCall(DMGetLabel(dm, name, &label)); 1978 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1979 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1980 PetscCall(VecView(val, viewer)); 1981 PetscCall(VecDestroy(&val)); 1982 } 1983 PetscFunctionReturn(PETSC_SUCCESS); 1984 } 1985 1986 /*@ 1987 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1988 1989 Collective 1990 1991 Input Parameters: 1992 + dm - The `DM` whose topology is to be saved 1993 - viewer - The `PetscViewer` to save it in 1994 1995 Level: advanced 1996 1997 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1998 @*/ 1999 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2000 { 2001 PetscBool ishdf5; 2002 2003 PetscFunctionBegin; 2004 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2005 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2006 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2007 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2008 if (ishdf5) { 2009 #if defined(PETSC_HAVE_HDF5) 2010 PetscViewerFormat format; 2011 PetscCall(PetscViewerGetFormat(viewer, &format)); 2012 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2013 IS globalPointNumbering; 2014 2015 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2016 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2017 PetscCall(ISDestroy(&globalPointNumbering)); 2018 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2019 #else 2020 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2021 #endif 2022 } 2023 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2024 PetscFunctionReturn(PETSC_SUCCESS); 2025 } 2026 2027 /*@ 2028 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2029 2030 Collective 2031 2032 Input Parameters: 2033 + dm - The `DM` whose coordinates are to be saved 2034 - viewer - The `PetscViewer` for saving 2035 2036 Level: advanced 2037 2038 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2039 @*/ 2040 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2041 { 2042 PetscBool ishdf5; 2043 2044 PetscFunctionBegin; 2045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2046 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2047 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2048 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2049 if (ishdf5) { 2050 #if defined(PETSC_HAVE_HDF5) 2051 PetscViewerFormat format; 2052 PetscCall(PetscViewerGetFormat(viewer, &format)); 2053 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2054 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2055 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2056 #else 2057 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2058 #endif 2059 } 2060 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2061 PetscFunctionReturn(PETSC_SUCCESS); 2062 } 2063 2064 /*@ 2065 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2066 2067 Collective 2068 2069 Input Parameters: 2070 + dm - The `DM` whose labels are to be saved 2071 - viewer - The `PetscViewer` for saving 2072 2073 Level: advanced 2074 2075 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2076 @*/ 2077 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2078 { 2079 PetscBool ishdf5; 2080 2081 PetscFunctionBegin; 2082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2083 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2084 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2085 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2086 if (ishdf5) { 2087 #if defined(PETSC_HAVE_HDF5) 2088 IS globalPointNumbering; 2089 PetscViewerFormat format; 2090 2091 PetscCall(PetscViewerGetFormat(viewer, &format)); 2092 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2093 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2094 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2095 PetscCall(ISDestroy(&globalPointNumbering)); 2096 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2097 #else 2098 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2099 #endif 2100 } 2101 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2102 PetscFunctionReturn(PETSC_SUCCESS); 2103 } 2104 2105 /*@ 2106 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2107 2108 Collective 2109 2110 Input Parameters: 2111 + dm - The `DM` that contains the topology on which the section to be saved is defined 2112 . viewer - The `PetscViewer` for saving 2113 - sectiondm - The `DM` that contains the section to be saved 2114 2115 Level: advanced 2116 2117 Notes: 2118 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (`dm`) points. When the topology (`dm`) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 2119 2120 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2121 2122 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2123 @*/ 2124 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2125 { 2126 PetscBool ishdf5; 2127 2128 PetscFunctionBegin; 2129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2130 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2131 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2132 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2133 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2134 if (ishdf5) { 2135 #if defined(PETSC_HAVE_HDF5) 2136 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2137 #else 2138 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2139 #endif 2140 } 2141 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2142 PetscFunctionReturn(PETSC_SUCCESS); 2143 } 2144 2145 /*@ 2146 DMPlexGlobalVectorView - Saves a global vector 2147 2148 Collective 2149 2150 Input Parameters: 2151 + dm - The `DM` that represents the topology 2152 . viewer - The `PetscViewer` to save data with 2153 . sectiondm - The `DM` that contains the global section on which vec is defined 2154 - vec - The global vector to be saved 2155 2156 Level: advanced 2157 2158 Notes: 2159 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2160 2161 Calling sequence: 2162 .vb 2163 DMCreate(PETSC_COMM_WORLD, &dm); 2164 DMSetType(dm, DMPLEX); 2165 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2166 DMClone(dm, §iondm); 2167 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2168 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2169 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2170 PetscSectionSetChart(section, pStart, pEnd); 2171 PetscSectionSetUp(section); 2172 DMSetLocalSection(sectiondm, section); 2173 PetscSectionDestroy(§ion); 2174 DMGetGlobalVector(sectiondm, &vec); 2175 PetscObjectSetName((PetscObject)vec, "vec_name"); 2176 DMPlexTopologyView(dm, viewer); 2177 DMPlexSectionView(dm, viewer, sectiondm); 2178 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2179 DMRestoreGlobalVector(sectiondm, &vec); 2180 DMDestroy(§iondm); 2181 DMDestroy(&dm); 2182 .ve 2183 2184 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2185 @*/ 2186 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2187 { 2188 PetscBool ishdf5; 2189 2190 PetscFunctionBegin; 2191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2192 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2193 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2194 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2195 /* Check consistency */ 2196 { 2197 PetscSection section; 2198 PetscBool includesConstraints; 2199 PetscInt m, m1; 2200 2201 PetscCall(VecGetLocalSize(vec, &m1)); 2202 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2203 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2204 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2205 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2206 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2207 } 2208 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2209 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2210 if (ishdf5) { 2211 #if defined(PETSC_HAVE_HDF5) 2212 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2213 #else 2214 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2215 #endif 2216 } 2217 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2218 PetscFunctionReturn(PETSC_SUCCESS); 2219 } 2220 2221 /*@ 2222 DMPlexLocalVectorView - Saves a local vector 2223 2224 Collective 2225 2226 Input Parameters: 2227 + dm - The `DM` that represents the topology 2228 . viewer - The `PetscViewer` to save data with 2229 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2230 - vec - The local vector to be saved 2231 2232 Level: advanced 2233 2234 Note: 2235 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2236 2237 Calling sequence: 2238 .vb 2239 DMCreate(PETSC_COMM_WORLD, &dm); 2240 DMSetType(dm, DMPLEX); 2241 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2242 DMClone(dm, §iondm); 2243 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2244 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2245 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2246 PetscSectionSetChart(section, pStart, pEnd); 2247 PetscSectionSetUp(section); 2248 DMSetLocalSection(sectiondm, section); 2249 DMGetLocalVector(sectiondm, &vec); 2250 PetscObjectSetName((PetscObject)vec, "vec_name"); 2251 DMPlexTopologyView(dm, viewer); 2252 DMPlexSectionView(dm, viewer, sectiondm); 2253 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2254 DMRestoreLocalVector(sectiondm, &vec); 2255 DMDestroy(§iondm); 2256 DMDestroy(&dm); 2257 .ve 2258 2259 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2260 @*/ 2261 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2262 { 2263 PetscBool ishdf5; 2264 2265 PetscFunctionBegin; 2266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2267 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2268 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2269 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2270 /* Check consistency */ 2271 { 2272 PetscSection section; 2273 PetscBool includesConstraints; 2274 PetscInt m, m1; 2275 2276 PetscCall(VecGetLocalSize(vec, &m1)); 2277 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2278 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2279 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2280 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2281 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2282 } 2283 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2284 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2285 if (ishdf5) { 2286 #if defined(PETSC_HAVE_HDF5) 2287 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2288 #else 2289 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2290 #endif 2291 } 2292 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2293 PetscFunctionReturn(PETSC_SUCCESS); 2294 } 2295 2296 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2297 { 2298 PetscBool ishdf5; 2299 2300 PetscFunctionBegin; 2301 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2302 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2303 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2304 if (ishdf5) { 2305 #if defined(PETSC_HAVE_HDF5) 2306 PetscViewerFormat format; 2307 PetscCall(PetscViewerGetFormat(viewer, &format)); 2308 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2309 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2310 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2311 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2312 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2313 PetscFunctionReturn(PETSC_SUCCESS); 2314 #else 2315 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2316 #endif 2317 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2318 } 2319 2320 /*@ 2321 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2322 2323 Collective 2324 2325 Input Parameters: 2326 + dm - The `DM` into which the topology is loaded 2327 - viewer - The `PetscViewer` for the saved topology 2328 2329 Output Parameter: 2330 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded 2331 2332 Level: advanced 2333 2334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2335 `PetscViewer`, `PetscSF` 2336 @*/ 2337 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2338 { 2339 PetscBool ishdf5; 2340 2341 PetscFunctionBegin; 2342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2343 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2344 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2345 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2346 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2347 if (ishdf5) { 2348 #if defined(PETSC_HAVE_HDF5) 2349 PetscViewerFormat format; 2350 PetscCall(PetscViewerGetFormat(viewer, &format)); 2351 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2352 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2353 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2354 #else 2355 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2356 #endif 2357 } 2358 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2359 PetscFunctionReturn(PETSC_SUCCESS); 2360 } 2361 2362 /*@ 2363 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2364 2365 Collective 2366 2367 Input Parameters: 2368 + dm - The `DM` into which the coordinates are loaded 2369 . viewer - The `PetscViewer` for the saved coordinates 2370 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2371 2372 Level: advanced 2373 2374 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2375 `PetscSF`, `PetscViewer` 2376 @*/ 2377 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2378 { 2379 PetscBool ishdf5; 2380 2381 PetscFunctionBegin; 2382 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2383 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2384 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2385 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2386 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2387 if (ishdf5) { 2388 #if defined(PETSC_HAVE_HDF5) 2389 PetscViewerFormat format; 2390 PetscCall(PetscViewerGetFormat(viewer, &format)); 2391 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2392 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2393 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2394 #else 2395 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2396 #endif 2397 } 2398 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2399 PetscFunctionReturn(PETSC_SUCCESS); 2400 } 2401 2402 /*@ 2403 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2404 2405 Collective 2406 2407 Input Parameters: 2408 + dm - The `DM` into which the labels are loaded 2409 . viewer - The `PetscViewer` for the saved labels 2410 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2411 2412 Level: advanced 2413 2414 Note: 2415 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2416 2417 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2418 `PetscSF`, `PetscViewer` 2419 @*/ 2420 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2421 { 2422 PetscBool ishdf5; 2423 2424 PetscFunctionBegin; 2425 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2426 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2427 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2428 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2429 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2430 if (ishdf5) { 2431 #if defined(PETSC_HAVE_HDF5) 2432 PetscViewerFormat format; 2433 2434 PetscCall(PetscViewerGetFormat(viewer, &format)); 2435 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2436 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2437 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2438 #else 2439 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2440 #endif 2441 } 2442 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2443 PetscFunctionReturn(PETSC_SUCCESS); 2444 } 2445 2446 /*@ 2447 DMPlexSectionLoad - Loads section into a `DMPLEX` 2448 2449 Collective 2450 2451 Input Parameters: 2452 + dm - The `DM` that represents the topology 2453 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2454 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2455 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2456 2457 Output Parameters: 2458 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2459 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2460 2461 Level: advanced 2462 2463 Notes: 2464 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2465 2466 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2467 2468 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2469 2470 Example using 2 processes: 2471 .vb 2472 NX (number of points on dm): 4 2473 sectionA : the on-disk section 2474 vecA : a vector associated with sectionA 2475 sectionB : sectiondm's local section constructed in this function 2476 vecB (local) : a vector associated with sectiondm's local section 2477 vecB (global) : a vector associated with sectiondm's global section 2478 2479 rank 0 rank 1 2480 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2481 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2482 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2483 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2484 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2485 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2486 sectionB->atlasDof : 1 0 1 | 1 3 2487 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2488 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2489 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2490 .ve 2491 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2492 2493 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2494 @*/ 2495 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2496 { 2497 PetscBool ishdf5; 2498 2499 PetscFunctionBegin; 2500 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2501 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2502 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2503 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2504 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2505 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2506 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2507 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2508 if (ishdf5) { 2509 #if defined(PETSC_HAVE_HDF5) 2510 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2511 #else 2512 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2513 #endif 2514 } 2515 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2516 PetscFunctionReturn(PETSC_SUCCESS); 2517 } 2518 2519 /*@ 2520 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2521 2522 Collective 2523 2524 Input Parameters: 2525 + dm - The `DM` that represents the topology 2526 . viewer - The `PetscViewer` that represents the on-disk vector data 2527 . sectiondm - The `DM` that contains the global section on which vec is defined 2528 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2529 - vec - The global vector to set values of 2530 2531 Level: advanced 2532 2533 Notes: 2534 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2535 2536 Calling sequence: 2537 .vb 2538 DMCreate(PETSC_COMM_WORLD, &dm); 2539 DMSetType(dm, DMPLEX); 2540 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2541 DMPlexTopologyLoad(dm, viewer, &sfX); 2542 DMClone(dm, §iondm); 2543 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2544 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2545 DMGetGlobalVector(sectiondm, &vec); 2546 PetscObjectSetName((PetscObject)vec, "vec_name"); 2547 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2548 DMRestoreGlobalVector(sectiondm, &vec); 2549 PetscSFDestroy(&gsf); 2550 PetscSFDestroy(&sfX); 2551 DMDestroy(§iondm); 2552 DMDestroy(&dm); 2553 .ve 2554 2555 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2556 `PetscSF`, `PetscViewer` 2557 @*/ 2558 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2559 { 2560 PetscBool ishdf5; 2561 2562 PetscFunctionBegin; 2563 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2564 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2565 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2566 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2567 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2568 /* Check consistency */ 2569 { 2570 PetscSection section; 2571 PetscBool includesConstraints; 2572 PetscInt m, m1; 2573 2574 PetscCall(VecGetLocalSize(vec, &m1)); 2575 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2576 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2577 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2578 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2579 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2580 } 2581 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2582 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2583 if (ishdf5) { 2584 #if defined(PETSC_HAVE_HDF5) 2585 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2586 #else 2587 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2588 #endif 2589 } 2590 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2591 PetscFunctionReturn(PETSC_SUCCESS); 2592 } 2593 2594 /*@ 2595 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2596 2597 Collective 2598 2599 Input Parameters: 2600 + dm - The `DM` that represents the topology 2601 . viewer - The `PetscViewer` that represents the on-disk vector data 2602 . sectiondm - The `DM` that contains the local section on which vec is defined 2603 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2604 - vec - The local vector to set values of 2605 2606 Level: advanced 2607 2608 Notes: 2609 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2610 2611 Calling sequence: 2612 .vb 2613 DMCreate(PETSC_COMM_WORLD, &dm); 2614 DMSetType(dm, DMPLEX); 2615 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2616 DMPlexTopologyLoad(dm, viewer, &sfX); 2617 DMClone(dm, §iondm); 2618 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2619 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2620 DMGetLocalVector(sectiondm, &vec); 2621 PetscObjectSetName((PetscObject)vec, "vec_name"); 2622 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2623 DMRestoreLocalVector(sectiondm, &vec); 2624 PetscSFDestroy(&lsf); 2625 PetscSFDestroy(&sfX); 2626 DMDestroy(§iondm); 2627 DMDestroy(&dm); 2628 .ve 2629 2630 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2631 `PetscSF`, `PetscViewer` 2632 @*/ 2633 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2634 { 2635 PetscBool ishdf5; 2636 2637 PetscFunctionBegin; 2638 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2639 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2640 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2641 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2642 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2643 /* Check consistency */ 2644 { 2645 PetscSection section; 2646 PetscBool includesConstraints; 2647 PetscInt m, m1; 2648 2649 PetscCall(VecGetLocalSize(vec, &m1)); 2650 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2651 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2652 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2653 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2654 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2655 } 2656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2657 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2658 if (ishdf5) { 2659 #if defined(PETSC_HAVE_HDF5) 2660 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2661 #else 2662 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2663 #endif 2664 } 2665 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2666 PetscFunctionReturn(PETSC_SUCCESS); 2667 } 2668 2669 PetscErrorCode DMDestroy_Plex(DM dm) 2670 { 2671 DM_Plex *mesh = (DM_Plex *)dm->data; 2672 2673 PetscFunctionBegin; 2674 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2675 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2676 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2677 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2678 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2679 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2680 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2681 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2682 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2683 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2684 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2685 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2686 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2687 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2688 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2689 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2690 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2691 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2692 PetscCall(PetscFree(mesh->cones)); 2693 PetscCall(PetscFree(mesh->coneOrientations)); 2694 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2695 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2696 PetscCall(PetscFree(mesh->supports)); 2697 PetscCall(PetscFree(mesh->cellTypes)); 2698 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2699 PetscCall(PetscFree(mesh->tetgenOpts)); 2700 PetscCall(PetscFree(mesh->triangleOpts)); 2701 PetscCall(PetscFree(mesh->transformType)); 2702 PetscCall(PetscFree(mesh->distributionName)); 2703 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2704 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2705 PetscCall(ISDestroy(&mesh->subpointIS)); 2706 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2707 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2708 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2709 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2710 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2711 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2712 PetscCall(ISDestroy(&mesh->anchorIS)); 2713 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2714 PetscCall(PetscFree(mesh->parents)); 2715 PetscCall(PetscFree(mesh->childIDs)); 2716 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2717 PetscCall(PetscFree(mesh->children)); 2718 PetscCall(DMDestroy(&mesh->referenceTree)); 2719 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2720 PetscCall(PetscFree(mesh->neighbors)); 2721 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2722 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2723 PetscCall(PetscFree(mesh)); 2724 PetscFunctionReturn(PETSC_SUCCESS); 2725 } 2726 2727 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2728 { 2729 PetscSection sectionGlobal; 2730 PetscInt bs = -1, mbs; 2731 PetscInt localSize, localStart = 0; 2732 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2733 MatType mtype; 2734 ISLocalToGlobalMapping ltog; 2735 2736 PetscFunctionBegin; 2737 PetscCall(MatInitializePackage()); 2738 mtype = dm->mattype; 2739 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2740 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2741 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2742 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2743 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2744 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2745 PetscCall(MatSetType(*J, mtype)); 2746 PetscCall(MatSetFromOptions(*J)); 2747 PetscCall(MatGetBlockSize(*J, &mbs)); 2748 if (mbs > 1) bs = mbs; 2749 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2750 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2751 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2752 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2753 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2754 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2755 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2756 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2757 if (!isShell) { 2758 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2759 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2760 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2761 2762 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2763 2764 PetscCall(PetscCalloc1(localSize, &pblocks)); 2765 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2766 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2767 for (p = pStart; p < pEnd; ++p) { 2768 switch (dm->blocking_type) { 2769 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2770 PetscInt bdof, offset; 2771 2772 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2773 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2774 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2775 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2776 dof = dof < 0 ? -(dof + 1) : dof; 2777 bdof = cdof && (dof - cdof) ? 1 : dof; 2778 if (dof) { 2779 if (bs < 0) { 2780 bs = bdof; 2781 } else if (bs != bdof) { 2782 bs = 1; 2783 } 2784 } 2785 } break; 2786 case DM_BLOCKING_FIELD_NODE: { 2787 for (PetscInt field = 0; field < num_fields; field++) { 2788 PetscInt num_comp, bdof, offset; 2789 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2790 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2791 if (dof < 0) continue; 2792 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2793 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2794 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2795 PetscInt num_nodes = dof / num_comp; 2796 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2797 // Handle possibly constant block size (unlikely) 2798 bdof = cdof && (dof - cdof) ? 1 : dof; 2799 if (dof) { 2800 if (bs < 0) { 2801 bs = bdof; 2802 } else if (bs != bdof) { 2803 bs = 1; 2804 } 2805 } 2806 } 2807 } break; 2808 } 2809 } 2810 /* Must have same blocksize on all procs (some might have no points) */ 2811 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2812 bsLocal[1] = bs; 2813 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2814 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2815 else bs = bsMinMax[0]; 2816 bs = PetscMax(1, bs); 2817 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2818 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2819 PetscCall(MatSetBlockSize(*J, bs)); 2820 PetscCall(MatSetUp(*J)); 2821 } else { 2822 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2823 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2824 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2825 } 2826 { // Consolidate blocks 2827 PetscInt nblocks = 0; 2828 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2829 if (pblocks[i] == 0) continue; 2830 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2831 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2832 } 2833 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2834 } 2835 PetscCall(PetscFree(pblocks)); 2836 } 2837 PetscCall(MatSetDM(*J, dm)); 2838 PetscFunctionReturn(PETSC_SUCCESS); 2839 } 2840 2841 /*@ 2842 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2843 2844 Not Collective 2845 2846 Input Parameter: 2847 . dm - The `DMPLEX` 2848 2849 Output Parameter: 2850 . subsection - The subdomain section 2851 2852 Level: developer 2853 2854 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2855 @*/ 2856 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2857 { 2858 DM_Plex *mesh = (DM_Plex *)dm->data; 2859 2860 PetscFunctionBegin; 2861 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2862 if (!mesh->subdomainSection) { 2863 PetscSection section; 2864 PetscSF sf; 2865 2866 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2867 PetscCall(DMGetLocalSection(dm, §ion)); 2868 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2869 PetscCall(PetscSFDestroy(&sf)); 2870 } 2871 *subsection = mesh->subdomainSection; 2872 PetscFunctionReturn(PETSC_SUCCESS); 2873 } 2874 2875 /*@ 2876 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2877 2878 Not Collective 2879 2880 Input Parameter: 2881 . dm - The `DMPLEX` 2882 2883 Output Parameters: 2884 + pStart - The first mesh point 2885 - pEnd - The upper bound for mesh points 2886 2887 Level: beginner 2888 2889 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2890 @*/ 2891 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2892 { 2893 DM_Plex *mesh = (DM_Plex *)dm->data; 2894 2895 PetscFunctionBegin; 2896 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2897 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2898 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2899 PetscFunctionReturn(PETSC_SUCCESS); 2900 } 2901 2902 /*@ 2903 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2904 2905 Not Collective 2906 2907 Input Parameters: 2908 + dm - The `DMPLEX` 2909 . pStart - The first mesh point 2910 - pEnd - The upper bound for mesh points 2911 2912 Level: beginner 2913 2914 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2915 @*/ 2916 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2917 { 2918 DM_Plex *mesh = (DM_Plex *)dm->data; 2919 2920 PetscFunctionBegin; 2921 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2922 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2923 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2924 PetscCall(PetscFree(mesh->cellTypes)); 2925 PetscFunctionReturn(PETSC_SUCCESS); 2926 } 2927 2928 /*@ 2929 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2930 2931 Not Collective 2932 2933 Input Parameters: 2934 + dm - The `DMPLEX` 2935 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2936 2937 Output Parameter: 2938 . size - The cone size for point `p` 2939 2940 Level: beginner 2941 2942 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2943 @*/ 2944 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2945 { 2946 DM_Plex *mesh = (DM_Plex *)dm->data; 2947 2948 PetscFunctionBegin; 2949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2950 PetscAssertPointer(size, 3); 2951 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2952 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2953 PetscFunctionReturn(PETSC_SUCCESS); 2954 } 2955 2956 /*@ 2957 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2958 2959 Not Collective 2960 2961 Input Parameters: 2962 + dm - The `DMPLEX` 2963 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2964 - size - The cone size for point `p` 2965 2966 Level: beginner 2967 2968 Note: 2969 This should be called after `DMPlexSetChart()`. 2970 2971 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2972 @*/ 2973 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2974 { 2975 DM_Plex *mesh = (DM_Plex *)dm->data; 2976 2977 PetscFunctionBegin; 2978 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2979 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2980 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2981 PetscFunctionReturn(PETSC_SUCCESS); 2982 } 2983 2984 /*@C 2985 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2986 2987 Not Collective 2988 2989 Input Parameters: 2990 + dm - The `DMPLEX` 2991 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2992 2993 Output Parameter: 2994 . cone - An array of points which are on the in-edges for point `p` 2995 2996 Level: beginner 2997 2998 Fortran Notes: 2999 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3000 `DMPlexRestoreCone()` is not needed/available in C. 3001 3002 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3003 @*/ 3004 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3005 { 3006 DM_Plex *mesh = (DM_Plex *)dm->data; 3007 PetscInt off; 3008 3009 PetscFunctionBegin; 3010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3011 PetscAssertPointer(cone, 3); 3012 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3013 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3014 PetscFunctionReturn(PETSC_SUCCESS); 3015 } 3016 3017 /*@C 3018 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3019 3020 Not Collective 3021 3022 Input Parameters: 3023 + dm - The `DMPLEX` 3024 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3025 3026 Output Parameters: 3027 + pConesSection - `PetscSection` describing the layout of `pCones` 3028 - pCones - An array of points which are on the in-edges for the point set `p` 3029 3030 Level: intermediate 3031 3032 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3033 @*/ 3034 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3035 { 3036 PetscSection cs, newcs; 3037 PetscInt *cones; 3038 PetscInt *newarr = NULL; 3039 PetscInt n; 3040 3041 PetscFunctionBegin; 3042 PetscCall(DMPlexGetCones(dm, &cones)); 3043 PetscCall(DMPlexGetConeSection(dm, &cs)); 3044 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3045 if (pConesSection) *pConesSection = newcs; 3046 if (pCones) { 3047 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3048 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3049 } 3050 PetscFunctionReturn(PETSC_SUCCESS); 3051 } 3052 3053 /*@ 3054 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3055 3056 Not Collective 3057 3058 Input Parameters: 3059 + dm - The `DMPLEX` 3060 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3061 3062 Output Parameter: 3063 . expandedPoints - An array of vertices recursively expanded from input points 3064 3065 Level: advanced 3066 3067 Notes: 3068 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3069 3070 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3071 3072 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3073 `DMPlexGetDepth()`, `IS` 3074 @*/ 3075 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3076 { 3077 IS *expandedPointsAll; 3078 PetscInt depth; 3079 3080 PetscFunctionBegin; 3081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3082 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3083 PetscAssertPointer(expandedPoints, 3); 3084 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3085 *expandedPoints = expandedPointsAll[0]; 3086 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3087 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3088 PetscFunctionReturn(PETSC_SUCCESS); 3089 } 3090 3091 /*@ 3092 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 3093 3094 Not Collective 3095 3096 Input Parameters: 3097 + dm - The `DMPLEX` 3098 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3099 3100 Output Parameters: 3101 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3102 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3103 - sections - (optional) An array of sections which describe mappings from points to their cone points 3104 3105 Level: advanced 3106 3107 Notes: 3108 Like `DMPlexGetConeTuple()` but recursive. 3109 3110 Array `expandedPoints` has size equal to `depth`. Each `expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 3111 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3112 3113 Array section has size equal to `depth`. Each `PetscSection` `sections`[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows\: 3114 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3115 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3116 3117 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3118 `DMPlexGetDepth()`, `PetscSection`, `IS` 3119 @*/ 3120 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3121 { 3122 const PetscInt *arr0 = NULL, *cone = NULL; 3123 PetscInt *arr = NULL, *newarr = NULL; 3124 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3125 IS *expandedPoints_; 3126 PetscSection *sections_; 3127 3128 PetscFunctionBegin; 3129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3130 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3131 if (depth) PetscAssertPointer(depth, 3); 3132 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3133 if (sections) PetscAssertPointer(sections, 5); 3134 PetscCall(ISGetLocalSize(points, &n)); 3135 PetscCall(ISGetIndices(points, &arr0)); 3136 PetscCall(DMPlexGetDepth(dm, &depth_)); 3137 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3138 PetscCall(PetscCalloc1(depth_, §ions_)); 3139 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3140 for (d = depth_ - 1; d >= 0; d--) { 3141 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3142 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3143 for (i = 0; i < n; i++) { 3144 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3145 if (arr[i] >= start && arr[i] < end) { 3146 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3147 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3148 } else { 3149 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3150 } 3151 } 3152 PetscCall(PetscSectionSetUp(sections_[d])); 3153 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3154 PetscCall(PetscMalloc1(newn, &newarr)); 3155 for (i = 0; i < n; i++) { 3156 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3157 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3158 if (cn > 1) { 3159 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3160 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3161 } else { 3162 newarr[co] = arr[i]; 3163 } 3164 } 3165 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3166 arr = newarr; 3167 n = newn; 3168 } 3169 PetscCall(ISRestoreIndices(points, &arr0)); 3170 *depth = depth_; 3171 if (expandedPoints) *expandedPoints = expandedPoints_; 3172 else { 3173 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3174 PetscCall(PetscFree(expandedPoints_)); 3175 } 3176 if (sections) *sections = sections_; 3177 else { 3178 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3179 PetscCall(PetscFree(sections_)); 3180 } 3181 PetscFunctionReturn(PETSC_SUCCESS); 3182 } 3183 3184 /*@ 3185 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3186 3187 Not Collective 3188 3189 Input Parameters: 3190 + dm - The `DMPLEX` 3191 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3192 3193 Output Parameters: 3194 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3195 . expandedPoints - (optional) An array of recursively expanded cones 3196 - sections - (optional) An array of sections which describe mappings from points to their cone points 3197 3198 Level: advanced 3199 3200 Note: 3201 See `DMPlexGetConeRecursive()` 3202 3203 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3204 `DMPlexGetDepth()`, `IS`, `PetscSection` 3205 @*/ 3206 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3207 { 3208 PetscInt d, depth_; 3209 3210 PetscFunctionBegin; 3211 PetscCall(DMPlexGetDepth(dm, &depth_)); 3212 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3213 if (depth) *depth = 0; 3214 if (expandedPoints) { 3215 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3216 PetscCall(PetscFree(*expandedPoints)); 3217 } 3218 if (sections) { 3219 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3220 PetscCall(PetscFree(*sections)); 3221 } 3222 PetscFunctionReturn(PETSC_SUCCESS); 3223 } 3224 3225 /*@ 3226 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 3227 3228 Not Collective 3229 3230 Input Parameters: 3231 + dm - The `DMPLEX` 3232 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3233 - cone - An array of points which are on the in-edges for point `p` 3234 3235 Level: beginner 3236 3237 Note: 3238 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3239 3240 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3241 @*/ 3242 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3243 { 3244 DM_Plex *mesh = (DM_Plex *)dm->data; 3245 PetscInt dof, off, c; 3246 3247 PetscFunctionBegin; 3248 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3249 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3250 if (dof) PetscAssertPointer(cone, 3); 3251 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3252 if (PetscDefined(USE_DEBUG)) { 3253 PetscInt pStart, pEnd; 3254 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3255 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3256 for (c = 0; c < dof; ++c) { 3257 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3258 mesh->cones[off + c] = cone[c]; 3259 } 3260 } else { 3261 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3262 } 3263 PetscFunctionReturn(PETSC_SUCCESS); 3264 } 3265 3266 /*@C 3267 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3268 3269 Not Collective 3270 3271 Input Parameters: 3272 + dm - The `DMPLEX` 3273 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3274 3275 Output Parameter: 3276 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3277 integer giving the prescription for cone traversal. 3278 3279 Level: beginner 3280 3281 Note: 3282 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3283 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3284 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3285 with the identity. 3286 3287 Fortran Notes: 3288 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3289 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3290 3291 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3292 @*/ 3293 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3294 { 3295 DM_Plex *mesh = (DM_Plex *)dm->data; 3296 PetscInt off; 3297 3298 PetscFunctionBegin; 3299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3300 if (PetscDefined(USE_DEBUG)) { 3301 PetscInt dof; 3302 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3303 if (dof) PetscAssertPointer(coneOrientation, 3); 3304 } 3305 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3306 3307 *coneOrientation = &mesh->coneOrientations[off]; 3308 PetscFunctionReturn(PETSC_SUCCESS); 3309 } 3310 3311 /*@ 3312 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3313 3314 Not Collective 3315 3316 Input Parameters: 3317 + dm - The `DMPLEX` 3318 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3319 - coneOrientation - An array of orientations 3320 3321 Level: beginner 3322 3323 Notes: 3324 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3325 3326 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3327 3328 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3329 @*/ 3330 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3331 { 3332 DM_Plex *mesh = (DM_Plex *)dm->data; 3333 PetscInt pStart, pEnd; 3334 PetscInt dof, off, c; 3335 3336 PetscFunctionBegin; 3337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3338 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3339 if (dof) PetscAssertPointer(coneOrientation, 3); 3340 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3341 if (PetscDefined(USE_DEBUG)) { 3342 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3343 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3344 for (c = 0; c < dof; ++c) { 3345 PetscInt cdof, o = coneOrientation[c]; 3346 3347 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3348 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3349 mesh->coneOrientations[off + c] = o; 3350 } 3351 } else { 3352 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3353 } 3354 PetscFunctionReturn(PETSC_SUCCESS); 3355 } 3356 3357 /*@ 3358 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3359 3360 Not Collective 3361 3362 Input Parameters: 3363 + dm - The `DMPLEX` 3364 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3365 . conePos - The local index in the cone where the point should be put 3366 - conePoint - The mesh point to insert 3367 3368 Level: beginner 3369 3370 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3371 @*/ 3372 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3373 { 3374 DM_Plex *mesh = (DM_Plex *)dm->data; 3375 PetscInt pStart, pEnd; 3376 PetscInt dof, off; 3377 3378 PetscFunctionBegin; 3379 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3380 if (PetscDefined(USE_DEBUG)) { 3381 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3382 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3383 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3384 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3385 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3386 } 3387 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3388 mesh->cones[off + conePos] = conePoint; 3389 PetscFunctionReturn(PETSC_SUCCESS); 3390 } 3391 3392 /*@ 3393 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3394 3395 Not Collective 3396 3397 Input Parameters: 3398 + dm - The `DMPLEX` 3399 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3400 . conePos - The local index in the cone where the point should be put 3401 - coneOrientation - The point orientation to insert 3402 3403 Level: beginner 3404 3405 Note: 3406 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3407 3408 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3409 @*/ 3410 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3411 { 3412 DM_Plex *mesh = (DM_Plex *)dm->data; 3413 PetscInt pStart, pEnd; 3414 PetscInt dof, off; 3415 3416 PetscFunctionBegin; 3417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3418 if (PetscDefined(USE_DEBUG)) { 3419 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3420 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3421 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3422 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3423 } 3424 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3425 mesh->coneOrientations[off + conePos] = coneOrientation; 3426 PetscFunctionReturn(PETSC_SUCCESS); 3427 } 3428 3429 /*@C 3430 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3431 3432 Not collective 3433 3434 Input Parameters: 3435 + dm - The DMPlex 3436 - p - The point, which must lie in the chart set with DMPlexSetChart() 3437 3438 Output Parameters: 3439 + cone - An array of points which are on the in-edges for point `p` 3440 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3441 integer giving the prescription for cone traversal. 3442 3443 Level: beginner 3444 3445 Notes: 3446 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3447 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3448 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3449 with the identity. 3450 3451 Fortran Notes: 3452 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3453 `DMPlexRestoreCone()` is not needed/available in C. 3454 3455 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3456 @*/ 3457 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3458 { 3459 DM_Plex *mesh = (DM_Plex *)dm->data; 3460 3461 PetscFunctionBegin; 3462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3463 if (mesh->tr) { 3464 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3465 } else { 3466 PetscInt off; 3467 if (PetscDefined(USE_DEBUG)) { 3468 PetscInt dof; 3469 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3470 if (dof) { 3471 if (cone) PetscAssertPointer(cone, 3); 3472 if (ornt) PetscAssertPointer(ornt, 4); 3473 } 3474 } 3475 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3476 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3477 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3478 } 3479 PetscFunctionReturn(PETSC_SUCCESS); 3480 } 3481 3482 /*@C 3483 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3484 3485 Not Collective 3486 3487 Input Parameters: 3488 + dm - The DMPlex 3489 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3490 . cone - An array of points which are on the in-edges for point p 3491 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3492 integer giving the prescription for cone traversal. 3493 3494 Level: beginner 3495 3496 Notes: 3497 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3498 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3499 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3500 with the identity. 3501 3502 Fortran Notes: 3503 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3504 `DMPlexRestoreCone()` is not needed/available in C. 3505 3506 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3507 @*/ 3508 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3509 { 3510 DM_Plex *mesh = (DM_Plex *)dm->data; 3511 3512 PetscFunctionBegin; 3513 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3514 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3515 PetscFunctionReturn(PETSC_SUCCESS); 3516 } 3517 3518 /*@ 3519 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3520 3521 Not Collective 3522 3523 Input Parameters: 3524 + dm - The `DMPLEX` 3525 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3526 3527 Output Parameter: 3528 . size - The support size for point `p` 3529 3530 Level: beginner 3531 3532 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3533 @*/ 3534 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3535 { 3536 DM_Plex *mesh = (DM_Plex *)dm->data; 3537 3538 PetscFunctionBegin; 3539 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3540 PetscAssertPointer(size, 3); 3541 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3542 PetscFunctionReturn(PETSC_SUCCESS); 3543 } 3544 3545 /*@ 3546 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3547 3548 Not Collective 3549 3550 Input Parameters: 3551 + dm - The `DMPLEX` 3552 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3553 - size - The support size for point `p` 3554 3555 Level: beginner 3556 3557 Note: 3558 This should be called after `DMPlexSetChart()`. 3559 3560 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3561 @*/ 3562 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3563 { 3564 DM_Plex *mesh = (DM_Plex *)dm->data; 3565 3566 PetscFunctionBegin; 3567 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3568 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3569 PetscFunctionReturn(PETSC_SUCCESS); 3570 } 3571 3572 /*@C 3573 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3574 3575 Not Collective 3576 3577 Input Parameters: 3578 + dm - The `DMPLEX` 3579 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3580 3581 Output Parameter: 3582 . support - An array of points which are on the out-edges for point `p` 3583 3584 Level: beginner 3585 3586 Fortran Notes: 3587 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3588 `DMPlexRestoreSupport()` is not needed/available in C. 3589 3590 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3591 @*/ 3592 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3593 { 3594 DM_Plex *mesh = (DM_Plex *)dm->data; 3595 PetscInt off; 3596 3597 PetscFunctionBegin; 3598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3599 PetscAssertPointer(support, 3); 3600 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3601 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3602 PetscFunctionReturn(PETSC_SUCCESS); 3603 } 3604 3605 /*@ 3606 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3607 3608 Not Collective 3609 3610 Input Parameters: 3611 + dm - The `DMPLEX` 3612 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3613 - support - An array of points which are on the out-edges for point `p` 3614 3615 Level: beginner 3616 3617 Note: 3618 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3619 3620 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3621 @*/ 3622 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3623 { 3624 DM_Plex *mesh = (DM_Plex *)dm->data; 3625 PetscInt pStart, pEnd; 3626 PetscInt dof, off, c; 3627 3628 PetscFunctionBegin; 3629 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3630 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3631 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3632 if (dof) PetscAssertPointer(support, 3); 3633 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3634 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3635 for (c = 0; c < dof; ++c) { 3636 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3637 mesh->supports[off + c] = support[c]; 3638 } 3639 PetscFunctionReturn(PETSC_SUCCESS); 3640 } 3641 3642 /*@ 3643 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3644 3645 Not Collective 3646 3647 Input Parameters: 3648 + dm - The `DMPLEX` 3649 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3650 . supportPos - The local index in the cone where the point should be put 3651 - supportPoint - The mesh point to insert 3652 3653 Level: beginner 3654 3655 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3656 @*/ 3657 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3658 { 3659 DM_Plex *mesh = (DM_Plex *)dm->data; 3660 PetscInt pStart, pEnd; 3661 PetscInt dof, off; 3662 3663 PetscFunctionBegin; 3664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3665 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3666 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3667 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3668 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3669 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3670 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3671 mesh->supports[off + supportPos] = supportPoint; 3672 PetscFunctionReturn(PETSC_SUCCESS); 3673 } 3674 3675 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3676 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3677 { 3678 switch (ct) { 3679 case DM_POLYTOPE_SEGMENT: 3680 if (o == -1) return -2; 3681 break; 3682 case DM_POLYTOPE_TRIANGLE: 3683 if (o == -3) return -1; 3684 if (o == -2) return -3; 3685 if (o == -1) return -2; 3686 break; 3687 case DM_POLYTOPE_QUADRILATERAL: 3688 if (o == -4) return -2; 3689 if (o == -3) return -1; 3690 if (o == -2) return -4; 3691 if (o == -1) return -3; 3692 break; 3693 default: 3694 return o; 3695 } 3696 return o; 3697 } 3698 3699 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3700 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3701 { 3702 switch (ct) { 3703 case DM_POLYTOPE_SEGMENT: 3704 if ((o == -2) || (o == 1)) return -1; 3705 if (o == -1) return 0; 3706 break; 3707 case DM_POLYTOPE_TRIANGLE: 3708 if (o == -3) return -2; 3709 if (o == -2) return -1; 3710 if (o == -1) return -3; 3711 break; 3712 case DM_POLYTOPE_QUADRILATERAL: 3713 if (o == -4) return -2; 3714 if (o == -3) return -1; 3715 if (o == -2) return -4; 3716 if (o == -1) return -3; 3717 break; 3718 default: 3719 return o; 3720 } 3721 return o; 3722 } 3723 3724 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3725 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3726 { 3727 PetscInt pStart, pEnd, p; 3728 3729 PetscFunctionBegin; 3730 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3731 for (p = pStart; p < pEnd; ++p) { 3732 const PetscInt *cone, *ornt; 3733 PetscInt coneSize, c; 3734 3735 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3736 PetscCall(DMPlexGetCone(dm, p, &cone)); 3737 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3738 for (c = 0; c < coneSize; ++c) { 3739 DMPolytopeType ct; 3740 const PetscInt o = ornt[c]; 3741 3742 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3743 switch (ct) { 3744 case DM_POLYTOPE_SEGMENT: 3745 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3746 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3747 break; 3748 case DM_POLYTOPE_TRIANGLE: 3749 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3750 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3751 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3752 break; 3753 case DM_POLYTOPE_QUADRILATERAL: 3754 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3755 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3756 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3757 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3758 break; 3759 default: 3760 break; 3761 } 3762 } 3763 } 3764 PetscFunctionReturn(PETSC_SUCCESS); 3765 } 3766 3767 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3768 { 3769 DM_Plex *mesh = (DM_Plex *)dm->data; 3770 3771 PetscFunctionBeginHot; 3772 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3773 if (useCone) { 3774 PetscCall(DMPlexGetConeSize(dm, p, size)); 3775 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3776 } else { 3777 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3778 PetscCall(DMPlexGetSupport(dm, p, arr)); 3779 } 3780 } else { 3781 if (useCone) { 3782 const PetscSection s = mesh->coneSection; 3783 const PetscInt ps = p - s->pStart; 3784 const PetscInt off = s->atlasOff[ps]; 3785 3786 *size = s->atlasDof[ps]; 3787 *arr = mesh->cones + off; 3788 *ornt = mesh->coneOrientations + off; 3789 } else { 3790 const PetscSection s = mesh->supportSection; 3791 const PetscInt ps = p - s->pStart; 3792 const PetscInt off = s->atlasOff[ps]; 3793 3794 *size = s->atlasDof[ps]; 3795 *arr = mesh->supports + off; 3796 } 3797 } 3798 PetscFunctionReturn(PETSC_SUCCESS); 3799 } 3800 3801 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3802 { 3803 DM_Plex *mesh = (DM_Plex *)dm->data; 3804 3805 PetscFunctionBeginHot; 3806 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3807 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3808 } 3809 PetscFunctionReturn(PETSC_SUCCESS); 3810 } 3811 3812 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3813 { 3814 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3815 PetscInt *closure; 3816 const PetscInt *tmp = NULL, *tmpO = NULL; 3817 PetscInt off = 0, tmpSize, t; 3818 3819 PetscFunctionBeginHot; 3820 if (ornt) { 3821 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3822 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 3823 } 3824 if (*points) { 3825 closure = *points; 3826 } else { 3827 PetscInt maxConeSize, maxSupportSize; 3828 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3829 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3830 } 3831 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3832 if (ct == DM_POLYTOPE_UNKNOWN) { 3833 closure[off++] = p; 3834 closure[off++] = 0; 3835 for (t = 0; t < tmpSize; ++t) { 3836 closure[off++] = tmp[t]; 3837 closure[off++] = tmpO ? tmpO[t] : 0; 3838 } 3839 } else { 3840 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3841 3842 /* We assume that cells with a valid type have faces with a valid type */ 3843 closure[off++] = p; 3844 closure[off++] = ornt; 3845 for (t = 0; t < tmpSize; ++t) { 3846 DMPolytopeType ft; 3847 3848 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3849 closure[off++] = tmp[arr[t]]; 3850 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3851 } 3852 } 3853 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3854 if (numPoints) *numPoints = tmpSize + 1; 3855 if (points) *points = closure; 3856 PetscFunctionReturn(PETSC_SUCCESS); 3857 } 3858 3859 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3860 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3861 { 3862 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3863 const PetscInt *cone, *ornt; 3864 PetscInt *pts, *closure = NULL; 3865 DMPolytopeType ft; 3866 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3867 PetscInt dim, coneSize, c, d, clSize, cl; 3868 3869 PetscFunctionBeginHot; 3870 PetscCall(DMGetDimension(dm, &dim)); 3871 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3872 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3873 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3874 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3875 maxSize = PetscMax(coneSeries, supportSeries); 3876 if (*points) { 3877 pts = *points; 3878 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3879 c = 0; 3880 pts[c++] = point; 3881 pts[c++] = o; 3882 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3883 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3884 for (cl = 0; cl < clSize * 2; cl += 2) { 3885 pts[c++] = closure[cl]; 3886 pts[c++] = closure[cl + 1]; 3887 } 3888 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3889 for (cl = 0; cl < clSize * 2; cl += 2) { 3890 pts[c++] = closure[cl]; 3891 pts[c++] = closure[cl + 1]; 3892 } 3893 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3894 for (d = 2; d < coneSize; ++d) { 3895 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3896 pts[c++] = cone[arr[d * 2 + 0]]; 3897 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3898 } 3899 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3900 if (dim >= 3) { 3901 for (d = 2; d < coneSize; ++d) { 3902 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3903 const PetscInt *fcone, *fornt; 3904 PetscInt fconeSize, fc, i; 3905 3906 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3907 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3908 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3909 for (fc = 0; fc < fconeSize; ++fc) { 3910 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3911 const PetscInt co = farr[fc * 2 + 1]; 3912 3913 for (i = 0; i < c; i += 2) 3914 if (pts[i] == cp) break; 3915 if (i == c) { 3916 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3917 pts[c++] = cp; 3918 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3919 } 3920 } 3921 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3922 } 3923 } 3924 *numPoints = c / 2; 3925 *points = pts; 3926 PetscFunctionReturn(PETSC_SUCCESS); 3927 } 3928 3929 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3930 { 3931 DMPolytopeType ct; 3932 PetscInt *closure, *fifo; 3933 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3934 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3935 PetscInt depth, maxSize; 3936 3937 PetscFunctionBeginHot; 3938 PetscCall(DMPlexGetDepth(dm, &depth)); 3939 if (depth == 1) { 3940 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3941 PetscFunctionReturn(PETSC_SUCCESS); 3942 } 3943 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3944 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) ct = DM_POLYTOPE_UNKNOWN; 3945 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3946 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3947 PetscFunctionReturn(PETSC_SUCCESS); 3948 } 3949 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3950 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3951 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3952 maxSize = PetscMax(coneSeries, supportSeries); 3953 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3954 if (*points) { 3955 closure = *points; 3956 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3957 closure[closureSize++] = p; 3958 closure[closureSize++] = ornt; 3959 fifo[fifoSize++] = p; 3960 fifo[fifoSize++] = ornt; 3961 fifo[fifoSize++] = ct; 3962 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3963 while (fifoSize - fifoStart) { 3964 const PetscInt q = fifo[fifoStart++]; 3965 const PetscInt o = fifo[fifoStart++]; 3966 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3967 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 3968 const PetscInt *tmp, *tmpO = NULL; 3969 PetscInt tmpSize, t; 3970 3971 if (PetscDefined(USE_DEBUG)) { 3972 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 3973 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 3974 } 3975 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3976 for (t = 0; t < tmpSize; ++t) { 3977 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3978 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3979 const PetscInt cp = tmp[ip]; 3980 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3981 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3982 PetscInt c; 3983 3984 /* Check for duplicate */ 3985 for (c = 0; c < closureSize; c += 2) { 3986 if (closure[c] == cp) break; 3987 } 3988 if (c == closureSize) { 3989 closure[closureSize++] = cp; 3990 closure[closureSize++] = co; 3991 fifo[fifoSize++] = cp; 3992 fifo[fifoSize++] = co; 3993 fifo[fifoSize++] = ct; 3994 } 3995 } 3996 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3997 } 3998 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3999 if (numPoints) *numPoints = closureSize / 2; 4000 if (points) *points = closure; 4001 PetscFunctionReturn(PETSC_SUCCESS); 4002 } 4003 4004 /*@C 4005 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4006 4007 Not Collective 4008 4009 Input Parameters: 4010 + dm - The `DMPLEX` 4011 . p - The mesh point 4012 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4013 4014 Input/Output Parameter: 4015 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4016 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4017 4018 Output Parameter: 4019 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4020 4021 Level: beginner 4022 4023 Note: 4024 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4025 4026 Fortran Notes: 4027 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4028 4029 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4030 @*/ 4031 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4032 { 4033 PetscFunctionBeginHot; 4034 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4035 if (numPoints) PetscAssertPointer(numPoints, 4); 4036 if (points) PetscAssertPointer(points, 5); 4037 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4038 PetscFunctionReturn(PETSC_SUCCESS); 4039 } 4040 4041 /*@C 4042 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4043 4044 Not Collective 4045 4046 Input Parameters: 4047 + dm - The `DMPLEX` 4048 . p - The mesh point 4049 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4050 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4051 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4052 4053 Level: beginner 4054 4055 Note: 4056 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4057 4058 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4059 @*/ 4060 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4061 { 4062 PetscFunctionBeginHot; 4063 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4064 if (numPoints) *numPoints = 0; 4065 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4066 PetscFunctionReturn(PETSC_SUCCESS); 4067 } 4068 4069 /*@ 4070 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4071 4072 Not Collective 4073 4074 Input Parameter: 4075 . dm - The `DMPLEX` 4076 4077 Output Parameters: 4078 + maxConeSize - The maximum number of in-edges 4079 - maxSupportSize - The maximum number of out-edges 4080 4081 Level: beginner 4082 4083 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4084 @*/ 4085 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4086 { 4087 DM_Plex *mesh = (DM_Plex *)dm->data; 4088 4089 PetscFunctionBegin; 4090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4091 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4092 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4093 PetscFunctionReturn(PETSC_SUCCESS); 4094 } 4095 4096 PetscErrorCode DMSetUp_Plex(DM dm) 4097 { 4098 DM_Plex *mesh = (DM_Plex *)dm->data; 4099 PetscInt size, maxSupportSize; 4100 4101 PetscFunctionBegin; 4102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4103 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4104 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4105 PetscCall(PetscMalloc1(size, &mesh->cones)); 4106 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4107 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4108 if (maxSupportSize) { 4109 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4110 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4111 PetscCall(PetscMalloc1(size, &mesh->supports)); 4112 } 4113 PetscFunctionReturn(PETSC_SUCCESS); 4114 } 4115 4116 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4117 { 4118 PetscFunctionBegin; 4119 if (subdm) PetscCall(DMClone(dm, subdm)); 4120 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 4121 if (subdm) (*subdm)->useNatural = dm->useNatural; 4122 if (dm->useNatural && dm->sfMigration) { 4123 PetscSF sfNatural; 4124 4125 (*subdm)->sfMigration = dm->sfMigration; 4126 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4127 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4128 (*subdm)->sfNatural = sfNatural; 4129 } 4130 PetscFunctionReturn(PETSC_SUCCESS); 4131 } 4132 4133 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4134 { 4135 PetscInt i = 0; 4136 4137 PetscFunctionBegin; 4138 PetscCall(DMClone(dms[0], superdm)); 4139 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4140 (*superdm)->useNatural = PETSC_FALSE; 4141 for (i = 0; i < len; i++) { 4142 if (dms[i]->useNatural && dms[i]->sfMigration) { 4143 PetscSF sfNatural; 4144 4145 (*superdm)->sfMigration = dms[i]->sfMigration; 4146 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4147 (*superdm)->useNatural = PETSC_TRUE; 4148 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4149 (*superdm)->sfNatural = sfNatural; 4150 break; 4151 } 4152 } 4153 PetscFunctionReturn(PETSC_SUCCESS); 4154 } 4155 4156 /*@ 4157 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4158 4159 Not Collective 4160 4161 Input Parameter: 4162 . dm - The `DMPLEX` 4163 4164 Level: beginner 4165 4166 Note: 4167 This should be called after all calls to `DMPlexSetCone()` 4168 4169 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4170 @*/ 4171 PetscErrorCode DMPlexSymmetrize(DM dm) 4172 { 4173 DM_Plex *mesh = (DM_Plex *)dm->data; 4174 PetscInt *offsets; 4175 PetscInt supportSize; 4176 PetscInt pStart, pEnd, p; 4177 4178 PetscFunctionBegin; 4179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4180 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4181 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4182 /* Calculate support sizes */ 4183 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4184 for (p = pStart; p < pEnd; ++p) { 4185 PetscInt dof, off, c; 4186 4187 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4188 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4189 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4190 } 4191 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4192 /* Calculate supports */ 4193 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4194 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4195 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4196 for (p = pStart; p < pEnd; ++p) { 4197 PetscInt dof, off, c; 4198 4199 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4200 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4201 for (c = off; c < off + dof; ++c) { 4202 const PetscInt q = mesh->cones[c]; 4203 PetscInt offS; 4204 4205 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4206 4207 mesh->supports[offS + offsets[q]] = p; 4208 ++offsets[q]; 4209 } 4210 } 4211 PetscCall(PetscFree(offsets)); 4212 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4213 PetscFunctionReturn(PETSC_SUCCESS); 4214 } 4215 4216 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4217 { 4218 IS stratumIS; 4219 4220 PetscFunctionBegin; 4221 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4222 if (PetscDefined(USE_DEBUG)) { 4223 PetscInt qStart, qEnd, numLevels, level; 4224 PetscBool overlap = PETSC_FALSE; 4225 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4226 for (level = 0; level < numLevels; level++) { 4227 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4228 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4229 overlap = PETSC_TRUE; 4230 break; 4231 } 4232 } 4233 PetscCheck(!overlap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 4234 } 4235 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4236 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4237 PetscCall(ISDestroy(&stratumIS)); 4238 PetscFunctionReturn(PETSC_SUCCESS); 4239 } 4240 4241 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4242 { 4243 PetscInt *pMin, *pMax; 4244 PetscInt pStart, pEnd; 4245 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4246 4247 PetscFunctionBegin; 4248 { 4249 DMLabel label2; 4250 4251 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4252 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4253 } 4254 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4255 for (PetscInt p = pStart; p < pEnd; ++p) { 4256 DMPolytopeType ct; 4257 4258 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4259 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4260 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4261 } 4262 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4263 for (PetscInt d = dmin; d <= dmax; ++d) { 4264 pMin[d] = PETSC_MAX_INT; 4265 pMax[d] = PETSC_MIN_INT; 4266 } 4267 for (PetscInt p = pStart; p < pEnd; ++p) { 4268 DMPolytopeType ct; 4269 PetscInt d; 4270 4271 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4272 d = DMPolytopeTypeGetDim(ct); 4273 pMin[d] = PetscMin(p, pMin[d]); 4274 pMax[d] = PetscMax(p, pMax[d]); 4275 } 4276 for (PetscInt d = dmin; d <= dmax; ++d) { 4277 if (pMin[d] > pMax[d]) continue; 4278 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4279 } 4280 PetscCall(PetscFree2(pMin, pMax)); 4281 PetscFunctionReturn(PETSC_SUCCESS); 4282 } 4283 4284 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4285 { 4286 PetscInt pStart, pEnd; 4287 PetscInt numRoots = 0, numLeaves = 0; 4288 4289 PetscFunctionBegin; 4290 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4291 { 4292 /* Initialize roots and count leaves */ 4293 PetscInt sMin = PETSC_MAX_INT; 4294 PetscInt sMax = PETSC_MIN_INT; 4295 PetscInt coneSize, supportSize; 4296 4297 for (PetscInt p = pStart; p < pEnd; ++p) { 4298 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4299 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4300 if (!coneSize && supportSize) { 4301 sMin = PetscMin(p, sMin); 4302 sMax = PetscMax(p, sMax); 4303 ++numRoots; 4304 } else if (!supportSize && coneSize) { 4305 ++numLeaves; 4306 } else if (!supportSize && !coneSize) { 4307 /* Isolated points */ 4308 sMin = PetscMin(p, sMin); 4309 sMax = PetscMax(p, sMax); 4310 } 4311 } 4312 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4313 } 4314 4315 if (numRoots + numLeaves == (pEnd - pStart)) { 4316 PetscInt sMin = PETSC_MAX_INT; 4317 PetscInt sMax = PETSC_MIN_INT; 4318 PetscInt coneSize, supportSize; 4319 4320 for (PetscInt p = pStart; p < pEnd; ++p) { 4321 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4322 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4323 if (!supportSize && coneSize) { 4324 sMin = PetscMin(p, sMin); 4325 sMax = PetscMax(p, sMax); 4326 } 4327 } 4328 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4329 } else { 4330 PetscInt level = 0; 4331 PetscInt qStart, qEnd; 4332 4333 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4334 while (qEnd > qStart) { 4335 PetscInt sMin = PETSC_MAX_INT; 4336 PetscInt sMax = PETSC_MIN_INT; 4337 4338 for (PetscInt q = qStart; q < qEnd; ++q) { 4339 const PetscInt *support; 4340 PetscInt supportSize; 4341 4342 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4343 PetscCall(DMPlexGetSupport(dm, q, &support)); 4344 for (PetscInt s = 0; s < supportSize; ++s) { 4345 sMin = PetscMin(support[s], sMin); 4346 sMax = PetscMax(support[s], sMax); 4347 } 4348 } 4349 PetscCall(DMLabelGetNumValues(label, &level)); 4350 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4351 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4352 } 4353 } 4354 PetscFunctionReturn(PETSC_SUCCESS); 4355 } 4356 4357 /*@ 4358 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4359 4360 Collective 4361 4362 Input Parameter: 4363 . dm - The `DMPLEX` 4364 4365 Level: beginner 4366 4367 Notes: 4368 The strata group all points of the same grade, and this function calculates the strata. This 4369 grade can be seen as the height (or depth) of the point in the DAG. 4370 4371 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4372 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4373 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4374 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4375 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4376 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4377 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4378 4379 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4380 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4381 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 4382 to interpolate only that one (e0), so that 4383 .vb 4384 cone(c0) = {e0, v2} 4385 cone(e0) = {v0, v1} 4386 .ve 4387 If `DMPlexStratify()` is run on this mesh, it will give depths 4388 .vb 4389 depth 0 = {v0, v1, v2} 4390 depth 1 = {e0, c0} 4391 .ve 4392 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4393 4394 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4395 4396 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4397 @*/ 4398 PetscErrorCode DMPlexStratify(DM dm) 4399 { 4400 DM_Plex *mesh = (DM_Plex *)dm->data; 4401 DMLabel label; 4402 PetscBool flg = PETSC_FALSE; 4403 4404 PetscFunctionBegin; 4405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4406 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4407 4408 // Create depth label 4409 PetscCall(DMCreateLabel(dm, "depth")); 4410 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4411 4412 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4413 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4414 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4415 4416 { /* just in case there is an empty process */ 4417 PetscInt numValues, maxValues = 0, v; 4418 4419 PetscCall(DMLabelGetNumValues(label, &numValues)); 4420 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4421 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4422 } 4423 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4424 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4425 PetscFunctionReturn(PETSC_SUCCESS); 4426 } 4427 4428 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4429 { 4430 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4431 PetscInt dim, depth, pheight, coneSize; 4432 4433 PetscFunctionBeginHot; 4434 PetscCall(DMGetDimension(dm, &dim)); 4435 PetscCall(DMPlexGetDepth(dm, &depth)); 4436 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4437 pheight = depth - pdepth; 4438 if (depth <= 1) { 4439 switch (pdepth) { 4440 case 0: 4441 ct = DM_POLYTOPE_POINT; 4442 break; 4443 case 1: 4444 switch (coneSize) { 4445 case 2: 4446 ct = DM_POLYTOPE_SEGMENT; 4447 break; 4448 case 3: 4449 ct = DM_POLYTOPE_TRIANGLE; 4450 break; 4451 case 4: 4452 switch (dim) { 4453 case 2: 4454 ct = DM_POLYTOPE_QUADRILATERAL; 4455 break; 4456 case 3: 4457 ct = DM_POLYTOPE_TETRAHEDRON; 4458 break; 4459 default: 4460 break; 4461 } 4462 break; 4463 case 5: 4464 ct = DM_POLYTOPE_PYRAMID; 4465 break; 4466 case 6: 4467 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4468 break; 4469 case 8: 4470 ct = DM_POLYTOPE_HEXAHEDRON; 4471 break; 4472 default: 4473 break; 4474 } 4475 } 4476 } else { 4477 if (pdepth == 0) { 4478 ct = DM_POLYTOPE_POINT; 4479 } else if (pheight == 0) { 4480 switch (dim) { 4481 case 1: 4482 switch (coneSize) { 4483 case 2: 4484 ct = DM_POLYTOPE_SEGMENT; 4485 break; 4486 default: 4487 break; 4488 } 4489 break; 4490 case 2: 4491 switch (coneSize) { 4492 case 3: 4493 ct = DM_POLYTOPE_TRIANGLE; 4494 break; 4495 case 4: 4496 ct = DM_POLYTOPE_QUADRILATERAL; 4497 break; 4498 default: 4499 break; 4500 } 4501 break; 4502 case 3: 4503 switch (coneSize) { 4504 case 4: 4505 ct = DM_POLYTOPE_TETRAHEDRON; 4506 break; 4507 case 5: { 4508 const PetscInt *cone; 4509 PetscInt faceConeSize; 4510 4511 PetscCall(DMPlexGetCone(dm, p, &cone)); 4512 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4513 switch (faceConeSize) { 4514 case 3: 4515 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4516 break; 4517 case 4: 4518 ct = DM_POLYTOPE_PYRAMID; 4519 break; 4520 } 4521 } break; 4522 case 6: 4523 ct = DM_POLYTOPE_HEXAHEDRON; 4524 break; 4525 default: 4526 break; 4527 } 4528 break; 4529 default: 4530 break; 4531 } 4532 } else if (pheight > 0) { 4533 switch (coneSize) { 4534 case 2: 4535 ct = DM_POLYTOPE_SEGMENT; 4536 break; 4537 case 3: 4538 ct = DM_POLYTOPE_TRIANGLE; 4539 break; 4540 case 4: 4541 ct = DM_POLYTOPE_QUADRILATERAL; 4542 break; 4543 default: 4544 break; 4545 } 4546 } 4547 } 4548 *pt = ct; 4549 PetscFunctionReturn(PETSC_SUCCESS); 4550 } 4551 4552 /*@ 4553 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4554 4555 Collective 4556 4557 Input Parameter: 4558 . dm - The `DMPLEX` 4559 4560 Level: developer 4561 4562 Note: 4563 This function is normally called automatically when a cell type is requested. It creates an 4564 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4565 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4566 4567 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4568 4569 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4570 @*/ 4571 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4572 { 4573 DM_Plex *mesh; 4574 DMLabel ctLabel; 4575 PetscInt pStart, pEnd, p; 4576 4577 PetscFunctionBegin; 4578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4579 mesh = (DM_Plex *)dm->data; 4580 PetscCall(DMCreateLabel(dm, "celltype")); 4581 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4582 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4583 PetscCall(PetscFree(mesh->cellTypes)); 4584 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4585 for (p = pStart; p < pEnd; ++p) { 4586 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4587 PetscInt pdepth; 4588 4589 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4590 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4591 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4592 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4593 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4594 } 4595 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4596 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4597 PetscFunctionReturn(PETSC_SUCCESS); 4598 } 4599 4600 /*@C 4601 DMPlexGetJoin - Get an array for the join of the set of points 4602 4603 Not Collective 4604 4605 Input Parameters: 4606 + dm - The `DMPLEX` object 4607 . numPoints - The number of input points for the join 4608 - points - The input points 4609 4610 Output Parameters: 4611 + numCoveredPoints - The number of points in the join 4612 - coveredPoints - The points in the join 4613 4614 Level: intermediate 4615 4616 Note: 4617 Currently, this is restricted to a single level join 4618 4619 Fortran Notes: 4620 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4621 4622 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4623 @*/ 4624 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4625 { 4626 DM_Plex *mesh = (DM_Plex *)dm->data; 4627 PetscInt *join[2]; 4628 PetscInt joinSize, i = 0; 4629 PetscInt dof, off, p, c, m; 4630 PetscInt maxSupportSize; 4631 4632 PetscFunctionBegin; 4633 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4634 PetscAssertPointer(points, 3); 4635 PetscAssertPointer(numCoveredPoints, 4); 4636 PetscAssertPointer(coveredPoints, 5); 4637 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4638 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4639 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4640 /* Copy in support of first point */ 4641 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4642 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4643 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4644 /* Check each successive support */ 4645 for (p = 1; p < numPoints; ++p) { 4646 PetscInt newJoinSize = 0; 4647 4648 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4649 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4650 for (c = 0; c < dof; ++c) { 4651 const PetscInt point = mesh->supports[off + c]; 4652 4653 for (m = 0; m < joinSize; ++m) { 4654 if (point == join[i][m]) { 4655 join[1 - i][newJoinSize++] = point; 4656 break; 4657 } 4658 } 4659 } 4660 joinSize = newJoinSize; 4661 i = 1 - i; 4662 } 4663 *numCoveredPoints = joinSize; 4664 *coveredPoints = join[i]; 4665 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4666 PetscFunctionReturn(PETSC_SUCCESS); 4667 } 4668 4669 /*@C 4670 DMPlexRestoreJoin - Restore an array for the join of the set of points 4671 4672 Not Collective 4673 4674 Input Parameters: 4675 + dm - The `DMPLEX` object 4676 . numPoints - The number of input points for the join 4677 - points - The input points 4678 4679 Output Parameters: 4680 + numCoveredPoints - The number of points in the join 4681 - coveredPoints - The points in the join 4682 4683 Level: intermediate 4684 4685 Fortran Notes: 4686 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4687 4688 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4689 @*/ 4690 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4691 { 4692 PetscFunctionBegin; 4693 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4694 if (points) PetscAssertPointer(points, 3); 4695 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4696 PetscAssertPointer(coveredPoints, 5); 4697 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4698 if (numCoveredPoints) *numCoveredPoints = 0; 4699 PetscFunctionReturn(PETSC_SUCCESS); 4700 } 4701 4702 /*@C 4703 DMPlexGetFullJoin - Get an array for the join of the set of points 4704 4705 Not Collective 4706 4707 Input Parameters: 4708 + dm - The `DMPLEX` object 4709 . numPoints - The number of input points for the join 4710 - points - The input points 4711 4712 Output Parameters: 4713 + numCoveredPoints - The number of points in the join 4714 - coveredPoints - The points in the join 4715 4716 Level: intermediate 4717 4718 Fortran Notes: 4719 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4720 4721 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4722 @*/ 4723 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4724 { 4725 PetscInt *offsets, **closures; 4726 PetscInt *join[2]; 4727 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4728 PetscInt p, d, c, m, ms; 4729 4730 PetscFunctionBegin; 4731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4732 PetscAssertPointer(points, 3); 4733 PetscAssertPointer(numCoveredPoints, 4); 4734 PetscAssertPointer(coveredPoints, 5); 4735 4736 PetscCall(DMPlexGetDepth(dm, &depth)); 4737 PetscCall(PetscCalloc1(numPoints, &closures)); 4738 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4739 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4740 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4741 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4742 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4743 4744 for (p = 0; p < numPoints; ++p) { 4745 PetscInt closureSize; 4746 4747 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4748 4749 offsets[p * (depth + 2) + 0] = 0; 4750 for (d = 0; d < depth + 1; ++d) { 4751 PetscInt pStart, pEnd, i; 4752 4753 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4754 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4755 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4756 offsets[p * (depth + 2) + d + 1] = i; 4757 break; 4758 } 4759 } 4760 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4761 } 4762 PetscCheck(offsets[p * (depth + 2) + depth + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (depth + 2) + depth + 1], closureSize); 4763 } 4764 for (d = 0; d < depth + 1; ++d) { 4765 PetscInt dof; 4766 4767 /* Copy in support of first point */ 4768 dof = offsets[d + 1] - offsets[d]; 4769 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4770 /* Check each successive cone */ 4771 for (p = 1; p < numPoints && joinSize; ++p) { 4772 PetscInt newJoinSize = 0; 4773 4774 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4775 for (c = 0; c < dof; ++c) { 4776 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4777 4778 for (m = 0; m < joinSize; ++m) { 4779 if (point == join[i][m]) { 4780 join[1 - i][newJoinSize++] = point; 4781 break; 4782 } 4783 } 4784 } 4785 joinSize = newJoinSize; 4786 i = 1 - i; 4787 } 4788 if (joinSize) break; 4789 } 4790 *numCoveredPoints = joinSize; 4791 *coveredPoints = join[i]; 4792 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4793 PetscCall(PetscFree(closures)); 4794 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4795 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4796 PetscFunctionReturn(PETSC_SUCCESS); 4797 } 4798 4799 /*@C 4800 DMPlexGetMeet - Get an array for the meet of the set of points 4801 4802 Not Collective 4803 4804 Input Parameters: 4805 + dm - The `DMPLEX` object 4806 . numPoints - The number of input points for the meet 4807 - points - The input points 4808 4809 Output Parameters: 4810 + numCoveringPoints - The number of points in the meet 4811 - coveringPoints - The points in the meet 4812 4813 Level: intermediate 4814 4815 Note: 4816 Currently, this is restricted to a single level meet 4817 4818 Fortran Notes: 4819 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4820 4821 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4822 @*/ 4823 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4824 { 4825 DM_Plex *mesh = (DM_Plex *)dm->data; 4826 PetscInt *meet[2]; 4827 PetscInt meetSize, i = 0; 4828 PetscInt dof, off, p, c, m; 4829 PetscInt maxConeSize; 4830 4831 PetscFunctionBegin; 4832 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4833 PetscAssertPointer(points, 3); 4834 PetscAssertPointer(numCoveringPoints, 4); 4835 PetscAssertPointer(coveringPoints, 5); 4836 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4837 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4838 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4839 /* Copy in cone of first point */ 4840 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4841 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4842 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4843 /* Check each successive cone */ 4844 for (p = 1; p < numPoints; ++p) { 4845 PetscInt newMeetSize = 0; 4846 4847 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4848 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4849 for (c = 0; c < dof; ++c) { 4850 const PetscInt point = mesh->cones[off + c]; 4851 4852 for (m = 0; m < meetSize; ++m) { 4853 if (point == meet[i][m]) { 4854 meet[1 - i][newMeetSize++] = point; 4855 break; 4856 } 4857 } 4858 } 4859 meetSize = newMeetSize; 4860 i = 1 - i; 4861 } 4862 *numCoveringPoints = meetSize; 4863 *coveringPoints = meet[i]; 4864 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4865 PetscFunctionReturn(PETSC_SUCCESS); 4866 } 4867 4868 /*@C 4869 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4870 4871 Not Collective 4872 4873 Input Parameters: 4874 + dm - The `DMPLEX` object 4875 . numPoints - The number of input points for the meet 4876 - points - The input points 4877 4878 Output Parameters: 4879 + numCoveredPoints - The number of points in the meet 4880 - coveredPoints - The points in the meet 4881 4882 Level: intermediate 4883 4884 Fortran Notes: 4885 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4886 4887 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4888 @*/ 4889 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4890 { 4891 PetscFunctionBegin; 4892 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4893 if (points) PetscAssertPointer(points, 3); 4894 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4895 PetscAssertPointer(coveredPoints, 5); 4896 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4897 if (numCoveredPoints) *numCoveredPoints = 0; 4898 PetscFunctionReturn(PETSC_SUCCESS); 4899 } 4900 4901 /*@C 4902 DMPlexGetFullMeet - Get an array for the meet of the set of points 4903 4904 Not Collective 4905 4906 Input Parameters: 4907 + dm - The `DMPLEX` object 4908 . numPoints - The number of input points for the meet 4909 - points - The input points 4910 4911 Output Parameters: 4912 + numCoveredPoints - The number of points in the meet 4913 - coveredPoints - The points in the meet 4914 4915 Level: intermediate 4916 4917 Fortran Notes: 4918 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4919 4920 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4921 @*/ 4922 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4923 { 4924 PetscInt *offsets, **closures; 4925 PetscInt *meet[2]; 4926 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4927 PetscInt p, h, c, m, mc; 4928 4929 PetscFunctionBegin; 4930 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4931 PetscAssertPointer(points, 3); 4932 PetscAssertPointer(numCoveredPoints, 4); 4933 PetscAssertPointer(coveredPoints, 5); 4934 4935 PetscCall(DMPlexGetDepth(dm, &height)); 4936 PetscCall(PetscMalloc1(numPoints, &closures)); 4937 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4938 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4939 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4940 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4941 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4942 4943 for (p = 0; p < numPoints; ++p) { 4944 PetscInt closureSize; 4945 4946 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4947 4948 offsets[p * (height + 2) + 0] = 0; 4949 for (h = 0; h < height + 1; ++h) { 4950 PetscInt pStart, pEnd, i; 4951 4952 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4953 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4954 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4955 offsets[p * (height + 2) + h + 1] = i; 4956 break; 4957 } 4958 } 4959 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4960 } 4961 PetscCheck(offsets[p * (height + 2) + height + 1] == closureSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p * (height + 2) + height + 1], closureSize); 4962 } 4963 for (h = 0; h < height + 1; ++h) { 4964 PetscInt dof; 4965 4966 /* Copy in cone of first point */ 4967 dof = offsets[h + 1] - offsets[h]; 4968 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4969 /* Check each successive cone */ 4970 for (p = 1; p < numPoints && meetSize; ++p) { 4971 PetscInt newMeetSize = 0; 4972 4973 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4974 for (c = 0; c < dof; ++c) { 4975 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4976 4977 for (m = 0; m < meetSize; ++m) { 4978 if (point == meet[i][m]) { 4979 meet[1 - i][newMeetSize++] = point; 4980 break; 4981 } 4982 } 4983 } 4984 meetSize = newMeetSize; 4985 i = 1 - i; 4986 } 4987 if (meetSize) break; 4988 } 4989 *numCoveredPoints = meetSize; 4990 *coveredPoints = meet[i]; 4991 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4992 PetscCall(PetscFree(closures)); 4993 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4994 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4995 PetscFunctionReturn(PETSC_SUCCESS); 4996 } 4997 4998 /*@C 4999 DMPlexEqual - Determine if two `DM` have the same topology 5000 5001 Not Collective 5002 5003 Input Parameters: 5004 + dmA - A `DMPLEX` object 5005 - dmB - A `DMPLEX` object 5006 5007 Output Parameter: 5008 . equal - `PETSC_TRUE` if the topologies are identical 5009 5010 Level: intermediate 5011 5012 Note: 5013 We are not solving graph isomorphism, so we do not permute. 5014 5015 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5016 @*/ 5017 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5018 { 5019 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5020 5021 PetscFunctionBegin; 5022 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5023 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5024 PetscAssertPointer(equal, 3); 5025 5026 *equal = PETSC_FALSE; 5027 PetscCall(DMPlexGetDepth(dmA, &depth)); 5028 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5029 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5030 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5031 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5032 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5033 for (p = pStart; p < pEnd; ++p) { 5034 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5035 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5036 5037 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5038 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5039 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5040 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5041 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5042 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5043 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5044 for (c = 0; c < coneSize; ++c) { 5045 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5046 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5047 } 5048 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5049 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5050 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5051 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5052 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5053 for (s = 0; s < supportSize; ++s) { 5054 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5055 } 5056 } 5057 *equal = PETSC_TRUE; 5058 PetscFunctionReturn(PETSC_SUCCESS); 5059 } 5060 5061 /*@C 5062 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5063 5064 Not Collective 5065 5066 Input Parameters: 5067 + dm - The `DMPLEX` 5068 . cellDim - The cell dimension 5069 - numCorners - The number of vertices on a cell 5070 5071 Output Parameter: 5072 . numFaceVertices - The number of vertices on a face 5073 5074 Level: developer 5075 5076 Note: 5077 Of course this can only work for a restricted set of symmetric shapes 5078 5079 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5080 @*/ 5081 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5082 { 5083 MPI_Comm comm; 5084 5085 PetscFunctionBegin; 5086 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5087 PetscAssertPointer(numFaceVertices, 4); 5088 switch (cellDim) { 5089 case 0: 5090 *numFaceVertices = 0; 5091 break; 5092 case 1: 5093 *numFaceVertices = 1; 5094 break; 5095 case 2: 5096 switch (numCorners) { 5097 case 3: /* triangle */ 5098 *numFaceVertices = 2; /* Edge has 2 vertices */ 5099 break; 5100 case 4: /* quadrilateral */ 5101 *numFaceVertices = 2; /* Edge has 2 vertices */ 5102 break; 5103 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5104 *numFaceVertices = 3; /* Edge has 3 vertices */ 5105 break; 5106 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5107 *numFaceVertices = 3; /* Edge has 3 vertices */ 5108 break; 5109 default: 5110 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5111 } 5112 break; 5113 case 3: 5114 switch (numCorners) { 5115 case 4: /* tetradehdron */ 5116 *numFaceVertices = 3; /* Face has 3 vertices */ 5117 break; 5118 case 6: /* tet cohesive cells */ 5119 *numFaceVertices = 4; /* Face has 4 vertices */ 5120 break; 5121 case 8: /* hexahedron */ 5122 *numFaceVertices = 4; /* Face has 4 vertices */ 5123 break; 5124 case 9: /* tet cohesive Lagrange cells */ 5125 *numFaceVertices = 6; /* Face has 6 vertices */ 5126 break; 5127 case 10: /* quadratic tetrahedron */ 5128 *numFaceVertices = 6; /* Face has 6 vertices */ 5129 break; 5130 case 12: /* hex cohesive Lagrange cells */ 5131 *numFaceVertices = 6; /* Face has 6 vertices */ 5132 break; 5133 case 18: /* quadratic tet cohesive Lagrange cells */ 5134 *numFaceVertices = 6; /* Face has 6 vertices */ 5135 break; 5136 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5137 *numFaceVertices = 9; /* Face has 9 vertices */ 5138 break; 5139 default: 5140 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5141 } 5142 break; 5143 default: 5144 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5145 } 5146 PetscFunctionReturn(PETSC_SUCCESS); 5147 } 5148 5149 /*@ 5150 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5151 5152 Not Collective 5153 5154 Input Parameter: 5155 . dm - The `DMPLEX` object 5156 5157 Output Parameter: 5158 . depthLabel - The `DMLabel` recording point depth 5159 5160 Level: developer 5161 5162 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5163 @*/ 5164 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5165 { 5166 PetscFunctionBegin; 5167 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5168 PetscAssertPointer(depthLabel, 2); 5169 *depthLabel = dm->depthLabel; 5170 PetscFunctionReturn(PETSC_SUCCESS); 5171 } 5172 5173 /*@ 5174 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5175 5176 Not Collective 5177 5178 Input Parameter: 5179 . dm - The `DMPLEX` object 5180 5181 Output Parameter: 5182 . depth - The number of strata (breadth first levels) in the DAG 5183 5184 Level: developer 5185 5186 Notes: 5187 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5188 5189 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5190 5191 An empty mesh gives -1. 5192 5193 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5194 @*/ 5195 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5196 { 5197 DM_Plex *mesh = (DM_Plex *)dm->data; 5198 DMLabel label; 5199 PetscInt d = 0; 5200 5201 PetscFunctionBegin; 5202 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5203 PetscAssertPointer(depth, 2); 5204 if (mesh->tr) { 5205 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5206 } else { 5207 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5208 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5209 *depth = d - 1; 5210 } 5211 PetscFunctionReturn(PETSC_SUCCESS); 5212 } 5213 5214 /*@ 5215 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5216 5217 Not Collective 5218 5219 Input Parameters: 5220 + dm - The `DMPLEX` object 5221 - depth - The requested depth 5222 5223 Output Parameters: 5224 + start - The first point at this `depth` 5225 - end - One beyond the last point at this `depth` 5226 5227 Level: developer 5228 5229 Notes: 5230 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5231 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5232 higher dimension, e.g., "edges". 5233 5234 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5235 @*/ 5236 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5237 { 5238 DM_Plex *mesh = (DM_Plex *)dm->data; 5239 DMLabel label; 5240 PetscInt pStart, pEnd; 5241 5242 PetscFunctionBegin; 5243 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5244 if (start) { 5245 PetscAssertPointer(start, 3); 5246 *start = 0; 5247 } 5248 if (end) { 5249 PetscAssertPointer(end, 4); 5250 *end = 0; 5251 } 5252 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5253 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5254 if (depth < 0) { 5255 if (start) *start = pStart; 5256 if (end) *end = pEnd; 5257 PetscFunctionReturn(PETSC_SUCCESS); 5258 } 5259 if (mesh->tr) { 5260 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5261 } else { 5262 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5263 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5264 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5265 } 5266 PetscFunctionReturn(PETSC_SUCCESS); 5267 } 5268 5269 /*@ 5270 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5271 5272 Not Collective 5273 5274 Input Parameters: 5275 + dm - The `DMPLEX` object 5276 - height - The requested height 5277 5278 Output Parameters: 5279 + start - The first point at this `height` 5280 - end - One beyond the last point at this `height` 5281 5282 Level: developer 5283 5284 Notes: 5285 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5286 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5287 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5288 5289 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5290 @*/ 5291 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5292 { 5293 DMLabel label; 5294 PetscInt depth, pStart, pEnd; 5295 5296 PetscFunctionBegin; 5297 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5298 if (start) { 5299 PetscAssertPointer(start, 3); 5300 *start = 0; 5301 } 5302 if (end) { 5303 PetscAssertPointer(end, 4); 5304 *end = 0; 5305 } 5306 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5307 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5308 if (height < 0) { 5309 if (start) *start = pStart; 5310 if (end) *end = pEnd; 5311 PetscFunctionReturn(PETSC_SUCCESS); 5312 } 5313 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5314 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5315 else PetscCall(DMGetDimension(dm, &depth)); 5316 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5317 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5318 PetscFunctionReturn(PETSC_SUCCESS); 5319 } 5320 5321 /*@ 5322 DMPlexGetPointDepth - Get the `depth` of a given point 5323 5324 Not Collective 5325 5326 Input Parameters: 5327 + dm - The `DMPLEX` object 5328 - point - The point 5329 5330 Output Parameter: 5331 . depth - The depth of the `point` 5332 5333 Level: intermediate 5334 5335 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5336 @*/ 5337 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5338 { 5339 PetscFunctionBegin; 5340 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5341 PetscAssertPointer(depth, 3); 5342 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5343 PetscFunctionReturn(PETSC_SUCCESS); 5344 } 5345 5346 /*@ 5347 DMPlexGetPointHeight - Get the `height` of a given point 5348 5349 Not Collective 5350 5351 Input Parameters: 5352 + dm - The `DMPLEX` object 5353 - point - The point 5354 5355 Output Parameter: 5356 . height - The height of the `point` 5357 5358 Level: intermediate 5359 5360 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5361 @*/ 5362 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5363 { 5364 PetscInt n, pDepth; 5365 5366 PetscFunctionBegin; 5367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5368 PetscAssertPointer(height, 3); 5369 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5370 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5371 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5372 PetscFunctionReturn(PETSC_SUCCESS); 5373 } 5374 5375 /*@ 5376 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5377 5378 Not Collective 5379 5380 Input Parameter: 5381 . dm - The `DMPLEX` object 5382 5383 Output Parameter: 5384 . celltypeLabel - The `DMLabel` recording cell polytope type 5385 5386 Level: developer 5387 5388 Note: 5389 This function will trigger automatica computation of cell types. This can be disabled by calling 5390 `DMCreateLabel`(dm, "celltype") beforehand. 5391 5392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5393 @*/ 5394 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5395 { 5396 PetscFunctionBegin; 5397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5398 PetscAssertPointer(celltypeLabel, 2); 5399 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5400 *celltypeLabel = dm->celltypeLabel; 5401 PetscFunctionReturn(PETSC_SUCCESS); 5402 } 5403 5404 /*@ 5405 DMPlexGetCellType - Get the polytope type of a given cell 5406 5407 Not Collective 5408 5409 Input Parameters: 5410 + dm - The `DMPLEX` object 5411 - cell - The cell 5412 5413 Output Parameter: 5414 . celltype - The polytope type of the cell 5415 5416 Level: intermediate 5417 5418 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5419 @*/ 5420 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5421 { 5422 DM_Plex *mesh = (DM_Plex *)dm->data; 5423 DMLabel label; 5424 PetscInt ct; 5425 5426 PetscFunctionBegin; 5427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5428 PetscAssertPointer(celltype, 3); 5429 if (mesh->tr) { 5430 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5431 } else { 5432 PetscInt pStart, pEnd; 5433 5434 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5435 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5436 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5437 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5438 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5439 for (PetscInt p = pStart; p < pEnd; p++) { 5440 PetscCall(DMLabelGetValue(label, p, &ct)); 5441 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5442 } 5443 } 5444 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5445 if (PetscDefined(USE_DEBUG)) { 5446 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5447 PetscCall(DMLabelGetValue(label, cell, &ct)); 5448 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5449 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5450 } 5451 } 5452 PetscFunctionReturn(PETSC_SUCCESS); 5453 } 5454 5455 /*@ 5456 DMPlexSetCellType - Set the polytope type of a given cell 5457 5458 Not Collective 5459 5460 Input Parameters: 5461 + dm - The `DMPLEX` object 5462 . cell - The cell 5463 - celltype - The polytope type of the cell 5464 5465 Level: advanced 5466 5467 Note: 5468 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5469 is executed. This function will override the computed type. However, if automatic classification will not succeed 5470 and a user wants to manually specify all types, the classification must be disabled by calling 5471 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5472 5473 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5474 @*/ 5475 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5476 { 5477 DM_Plex *mesh = (DM_Plex *)dm->data; 5478 DMLabel label; 5479 PetscInt pStart, pEnd; 5480 5481 PetscFunctionBegin; 5482 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5483 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5484 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5485 PetscCall(DMLabelSetValue(label, cell, celltype)); 5486 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5487 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5488 PetscFunctionReturn(PETSC_SUCCESS); 5489 } 5490 5491 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5492 { 5493 PetscSection section, s; 5494 Mat m; 5495 PetscInt maxHeight; 5496 const char *prefix; 5497 5498 PetscFunctionBegin; 5499 PetscCall(DMClone(dm, cdm)); 5500 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5501 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5502 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5503 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5504 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5505 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5506 PetscCall(DMSetLocalSection(*cdm, section)); 5507 PetscCall(PetscSectionDestroy(§ion)); 5508 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5509 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5510 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5511 PetscCall(PetscSectionDestroy(&s)); 5512 PetscCall(MatDestroy(&m)); 5513 5514 PetscCall(DMSetNumFields(*cdm, 1)); 5515 PetscCall(DMCreateDS(*cdm)); 5516 (*cdm)->cloneOpts = PETSC_TRUE; 5517 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5518 PetscFunctionReturn(PETSC_SUCCESS); 5519 } 5520 5521 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5522 { 5523 Vec coordsLocal, cellCoordsLocal; 5524 DM coordsDM, cellCoordsDM; 5525 5526 PetscFunctionBegin; 5527 *field = NULL; 5528 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5529 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5530 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5531 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5532 if (coordsLocal && coordsDM) { 5533 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5534 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5535 } 5536 PetscFunctionReturn(PETSC_SUCCESS); 5537 } 5538 5539 /*@C 5540 DMPlexGetConeSection - Return a section which describes the layout of cone data 5541 5542 Not Collective 5543 5544 Input Parameter: 5545 . dm - The `DMPLEX` object 5546 5547 Output Parameter: 5548 . section - The `PetscSection` object 5549 5550 Level: developer 5551 5552 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5553 @*/ 5554 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5555 { 5556 DM_Plex *mesh = (DM_Plex *)dm->data; 5557 5558 PetscFunctionBegin; 5559 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5560 if (section) *section = mesh->coneSection; 5561 PetscFunctionReturn(PETSC_SUCCESS); 5562 } 5563 5564 /*@C 5565 DMPlexGetSupportSection - Return a section which describes the layout of support data 5566 5567 Not Collective 5568 5569 Input Parameter: 5570 . dm - The `DMPLEX` object 5571 5572 Output Parameter: 5573 . section - The `PetscSection` object 5574 5575 Level: developer 5576 5577 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5578 @*/ 5579 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5580 { 5581 DM_Plex *mesh = (DM_Plex *)dm->data; 5582 5583 PetscFunctionBegin; 5584 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5585 if (section) *section = mesh->supportSection; 5586 PetscFunctionReturn(PETSC_SUCCESS); 5587 } 5588 5589 /*@C 5590 DMPlexGetCones - Return cone data 5591 5592 Not Collective 5593 5594 Input Parameter: 5595 . dm - The `DMPLEX` object 5596 5597 Output Parameter: 5598 . cones - The cone for each point 5599 5600 Level: developer 5601 5602 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5603 @*/ 5604 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5605 { 5606 DM_Plex *mesh = (DM_Plex *)dm->data; 5607 5608 PetscFunctionBegin; 5609 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5610 if (cones) *cones = mesh->cones; 5611 PetscFunctionReturn(PETSC_SUCCESS); 5612 } 5613 5614 /*@C 5615 DMPlexGetConeOrientations - Return cone orientation data 5616 5617 Not Collective 5618 5619 Input Parameter: 5620 . dm - The `DMPLEX` object 5621 5622 Output Parameter: 5623 . coneOrientations - The array of cone orientations for all points 5624 5625 Level: developer 5626 5627 Notes: 5628 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5629 5630 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5631 5632 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5633 @*/ 5634 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5635 { 5636 DM_Plex *mesh = (DM_Plex *)dm->data; 5637 5638 PetscFunctionBegin; 5639 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5640 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5641 PetscFunctionReturn(PETSC_SUCCESS); 5642 } 5643 5644 /******************************** FEM Support **********************************/ 5645 5646 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5647 { 5648 PetscInt depth; 5649 5650 PetscFunctionBegin; 5651 PetscCall(DMPlexGetDepth(plex, &depth)); 5652 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5653 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5654 PetscFunctionReturn(PETSC_SUCCESS); 5655 } 5656 5657 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5658 { 5659 PetscInt depth; 5660 5661 PetscFunctionBegin; 5662 PetscCall(DMPlexGetDepth(plex, &depth)); 5663 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5664 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5665 PetscFunctionReturn(PETSC_SUCCESS); 5666 } 5667 5668 /* 5669 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5670 representing a line in the section. 5671 */ 5672 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5673 { 5674 PetscObject obj; 5675 PetscClassId id; 5676 PetscFE fe = NULL; 5677 5678 PetscFunctionBeginHot; 5679 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5680 PetscCall(DMGetField(dm, field, NULL, &obj)); 5681 PetscCall(PetscObjectGetClassId(obj, &id)); 5682 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5683 5684 if (!fe) { 5685 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5686 /* An order k SEM disc has k-1 dofs on an edge */ 5687 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5688 *k = *k / *Nc + 1; 5689 } else { 5690 PetscInt dual_space_size, dim; 5691 PetscDualSpace dsp; 5692 5693 PetscCall(DMGetDimension(dm, &dim)); 5694 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5695 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5696 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5697 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5698 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5699 } 5700 PetscFunctionReturn(PETSC_SUCCESS); 5701 } 5702 5703 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5704 { 5705 PetscFunctionBeginHot; 5706 if (tensor) { 5707 *dof = PetscPowInt(k + 1, dim); 5708 } else { 5709 switch (dim) { 5710 case 1: 5711 *dof = k + 1; 5712 break; 5713 case 2: 5714 *dof = ((k + 1) * (k + 2)) / 2; 5715 break; 5716 case 3: 5717 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5718 break; 5719 default: 5720 *dof = 0; 5721 } 5722 } 5723 PetscFunctionReturn(PETSC_SUCCESS); 5724 } 5725 5726 /*@ 5727 5728 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5729 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5730 section provided (or the section of the `DM`). 5731 5732 Input Parameters: 5733 + dm - The `DM` 5734 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5735 - section - The `PetscSection` to reorder, or `NULL` for the default section 5736 5737 Example: 5738 A typical interpolated single-quad mesh might order points as 5739 .vb 5740 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5741 5742 v4 -- e6 -- v3 5743 | | 5744 e7 c0 e8 5745 | | 5746 v1 -- e5 -- v2 5747 .ve 5748 5749 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5750 dofs in the order of points, e.g., 5751 .vb 5752 c0 -> [0,1,2,3] 5753 v1 -> [4] 5754 ... 5755 e5 -> [8, 9] 5756 .ve 5757 5758 which corresponds to the dofs 5759 .vb 5760 6 10 11 7 5761 13 2 3 15 5762 12 0 1 14 5763 4 8 9 5 5764 .ve 5765 5766 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5767 .vb 5768 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5769 .ve 5770 5771 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5772 .vb 5773 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5774 .ve 5775 5776 Level: developer 5777 5778 Notes: 5779 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5780 degree of the basis. 5781 5782 This is required to run with libCEED. 5783 5784 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5785 @*/ 5786 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5787 { 5788 DMLabel label; 5789 PetscInt dim, depth = -1, eStart = -1, Nf; 5790 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5791 5792 PetscFunctionBegin; 5793 PetscCall(DMGetDimension(dm, &dim)); 5794 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5795 if (point < 0) { 5796 PetscInt sStart, sEnd; 5797 5798 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5799 point = sEnd - sStart ? sStart : point; 5800 } 5801 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5802 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5803 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5804 if (depth == 1) { 5805 eStart = point; 5806 } else if (depth == dim) { 5807 const PetscInt *cone; 5808 5809 PetscCall(DMPlexGetCone(dm, point, &cone)); 5810 if (dim == 2) eStart = cone[0]; 5811 else if (dim == 3) { 5812 const PetscInt *cone2; 5813 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5814 eStart = cone2[0]; 5815 } 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); 5816 } 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); 5817 5818 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5819 for (PetscInt d = 1; d <= dim; d++) { 5820 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5821 PetscInt *perm; 5822 5823 for (f = 0; f < Nf; ++f) { 5824 PetscInt dof; 5825 5826 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5827 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5828 if (!continuous && d < dim) continue; 5829 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5830 size += dof * Nc; 5831 } 5832 PetscCall(PetscMalloc1(size, &perm)); 5833 for (f = 0; f < Nf; ++f) { 5834 switch (d) { 5835 case 1: 5836 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5837 if (!continuous && d < dim) continue; 5838 /* 5839 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5840 We want [ vtx0; edge of length k-1; vtx1 ] 5841 */ 5842 if (continuous) { 5843 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5844 for (i = 0; i < k - 1; i++) 5845 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5846 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5847 foffset = offset; 5848 } else { 5849 PetscInt dof; 5850 5851 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5852 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5853 foffset = offset; 5854 } 5855 break; 5856 case 2: 5857 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5858 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5859 if (!continuous && d < dim) continue; 5860 /* The SEM order is 5861 5862 v_lb, {e_b}, v_rb, 5863 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5864 v_lt, reverse {e_t}, v_rt 5865 */ 5866 if (continuous) { 5867 const PetscInt of = 0; 5868 const PetscInt oeb = of + PetscSqr(k - 1); 5869 const PetscInt oer = oeb + (k - 1); 5870 const PetscInt oet = oer + (k - 1); 5871 const PetscInt oel = oet + (k - 1); 5872 const PetscInt ovlb = oel + (k - 1); 5873 const PetscInt ovrb = ovlb + 1; 5874 const PetscInt ovrt = ovrb + 1; 5875 const PetscInt ovlt = ovrt + 1; 5876 PetscInt o; 5877 5878 /* bottom */ 5879 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5880 for (o = oeb; o < oer; ++o) 5881 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5882 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5883 /* middle */ 5884 for (i = 0; i < k - 1; ++i) { 5885 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5886 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5887 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5888 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5889 } 5890 /* top */ 5891 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5892 for (o = oel - 1; o >= oet; --o) 5893 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5894 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5895 foffset = offset; 5896 } else { 5897 PetscInt dof; 5898 5899 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5900 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5901 foffset = offset; 5902 } 5903 break; 5904 case 3: 5905 /* The original hex closure is 5906 5907 {c, 5908 f_b, f_t, f_f, f_b, f_r, f_l, 5909 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5910 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5911 */ 5912 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5913 if (!continuous && d < dim) continue; 5914 /* The SEM order is 5915 Bottom Slice 5916 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5917 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5918 v_blb, {e_bb}, v_brb, 5919 5920 Middle Slice (j) 5921 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5922 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5923 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5924 5925 Top Slice 5926 v_tlf, {e_tf}, v_trf, 5927 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5928 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5929 */ 5930 if (continuous) { 5931 const PetscInt oc = 0; 5932 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5933 const PetscInt oft = ofb + PetscSqr(k - 1); 5934 const PetscInt off = oft + PetscSqr(k - 1); 5935 const PetscInt ofk = off + PetscSqr(k - 1); 5936 const PetscInt ofr = ofk + PetscSqr(k - 1); 5937 const PetscInt ofl = ofr + PetscSqr(k - 1); 5938 const PetscInt oebl = ofl + PetscSqr(k - 1); 5939 const PetscInt oebb = oebl + (k - 1); 5940 const PetscInt oebr = oebb + (k - 1); 5941 const PetscInt oebf = oebr + (k - 1); 5942 const PetscInt oetf = oebf + (k - 1); 5943 const PetscInt oetr = oetf + (k - 1); 5944 const PetscInt oetb = oetr + (k - 1); 5945 const PetscInt oetl = oetb + (k - 1); 5946 const PetscInt oerf = oetl + (k - 1); 5947 const PetscInt oelf = oerf + (k - 1); 5948 const PetscInt oelb = oelf + (k - 1); 5949 const PetscInt oerb = oelb + (k - 1); 5950 const PetscInt ovblf = oerb + (k - 1); 5951 const PetscInt ovblb = ovblf + 1; 5952 const PetscInt ovbrb = ovblb + 1; 5953 const PetscInt ovbrf = ovbrb + 1; 5954 const PetscInt ovtlf = ovbrf + 1; 5955 const PetscInt ovtrf = ovtlf + 1; 5956 const PetscInt ovtrb = ovtrf + 1; 5957 const PetscInt ovtlb = ovtrb + 1; 5958 PetscInt o, n; 5959 5960 /* Bottom Slice */ 5961 /* bottom */ 5962 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5963 for (o = oetf - 1; o >= oebf; --o) 5964 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5965 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5966 /* middle */ 5967 for (i = 0; i < k - 1; ++i) { 5968 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5969 for (n = 0; n < k - 1; ++n) { 5970 o = ofb + n * (k - 1) + i; 5971 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5972 } 5973 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5974 } 5975 /* top */ 5976 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5977 for (o = oebb; o < oebr; ++o) 5978 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5979 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5980 5981 /* Middle Slice */ 5982 for (j = 0; j < k - 1; ++j) { 5983 /* bottom */ 5984 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5985 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5986 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5987 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5988 /* middle */ 5989 for (i = 0; i < k - 1; ++i) { 5990 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5991 for (n = 0; n < k - 1; ++n) 5992 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5993 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5994 } 5995 /* top */ 5996 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5997 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5998 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5999 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6000 } 6001 6002 /* Top Slice */ 6003 /* bottom */ 6004 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6005 for (o = oetf; o < oetr; ++o) 6006 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6007 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6008 /* middle */ 6009 for (i = 0; i < k - 1; ++i) { 6010 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6011 for (n = 0; n < k - 1; ++n) 6012 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6013 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6014 } 6015 /* top */ 6016 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6017 for (o = oetl - 1; o >= oetb; --o) 6018 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6019 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6020 6021 foffset = offset; 6022 } else { 6023 PetscInt dof; 6024 6025 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6026 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6027 foffset = offset; 6028 } 6029 break; 6030 default: 6031 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6032 } 6033 } 6034 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6035 /* Check permutation */ 6036 { 6037 PetscInt *check; 6038 6039 PetscCall(PetscMalloc1(size, &check)); 6040 for (i = 0; i < size; ++i) { 6041 check[i] = -1; 6042 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6043 } 6044 for (i = 0; i < size; ++i) check[perm[i]] = i; 6045 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6046 PetscCall(PetscFree(check)); 6047 } 6048 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6049 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6050 PetscInt *loc_perm; 6051 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6052 for (PetscInt i = 0; i < size; i++) { 6053 loc_perm[i] = perm[i]; 6054 loc_perm[size + i] = size + perm[i]; 6055 } 6056 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6057 } 6058 } 6059 PetscFunctionReturn(PETSC_SUCCESS); 6060 } 6061 6062 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6063 { 6064 PetscDS prob; 6065 PetscInt depth, Nf, h; 6066 DMLabel label; 6067 6068 PetscFunctionBeginHot; 6069 PetscCall(DMGetDS(dm, &prob)); 6070 Nf = prob->Nf; 6071 label = dm->depthLabel; 6072 *dspace = NULL; 6073 if (field < Nf) { 6074 PetscObject disc = prob->disc[field]; 6075 6076 if (disc->classid == PETSCFE_CLASSID) { 6077 PetscDualSpace dsp; 6078 6079 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6080 PetscCall(DMLabelGetNumValues(label, &depth)); 6081 PetscCall(DMLabelGetValue(label, point, &h)); 6082 h = depth - 1 - h; 6083 if (h) { 6084 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6085 } else { 6086 *dspace = dsp; 6087 } 6088 } 6089 } 6090 PetscFunctionReturn(PETSC_SUCCESS); 6091 } 6092 6093 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6094 { 6095 PetscScalar *array; 6096 const PetscScalar *vArray; 6097 const PetscInt *cone, *coneO; 6098 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6099 6100 PetscFunctionBeginHot; 6101 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6102 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6103 PetscCall(DMPlexGetCone(dm, point, &cone)); 6104 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6105 if (!values || !*values) { 6106 if ((point >= pStart) && (point < pEnd)) { 6107 PetscInt dof; 6108 6109 PetscCall(PetscSectionGetDof(section, point, &dof)); 6110 size += dof; 6111 } 6112 for (p = 0; p < numPoints; ++p) { 6113 const PetscInt cp = cone[p]; 6114 PetscInt dof; 6115 6116 if ((cp < pStart) || (cp >= pEnd)) continue; 6117 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6118 size += dof; 6119 } 6120 if (!values) { 6121 if (csize) *csize = size; 6122 PetscFunctionReturn(PETSC_SUCCESS); 6123 } 6124 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6125 } else { 6126 array = *values; 6127 } 6128 size = 0; 6129 PetscCall(VecGetArrayRead(v, &vArray)); 6130 if ((point >= pStart) && (point < pEnd)) { 6131 PetscInt dof, off, d; 6132 const PetscScalar *varr; 6133 6134 PetscCall(PetscSectionGetDof(section, point, &dof)); 6135 PetscCall(PetscSectionGetOffset(section, point, &off)); 6136 varr = PetscSafePointerPlusOffset(vArray, off); 6137 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6138 size += dof; 6139 } 6140 for (p = 0; p < numPoints; ++p) { 6141 const PetscInt cp = cone[p]; 6142 PetscInt o = coneO[p]; 6143 PetscInt dof, off, d; 6144 const PetscScalar *varr; 6145 6146 if ((cp < pStart) || (cp >= pEnd)) continue; 6147 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6148 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6149 varr = PetscSafePointerPlusOffset(vArray, off); 6150 if (o >= 0) { 6151 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6152 } else { 6153 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6154 } 6155 size += dof; 6156 } 6157 PetscCall(VecRestoreArrayRead(v, &vArray)); 6158 if (!*values) { 6159 if (csize) *csize = size; 6160 *values = array; 6161 } else { 6162 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6163 *csize = size; 6164 } 6165 PetscFunctionReturn(PETSC_SUCCESS); 6166 } 6167 6168 /* Compress out points not in the section */ 6169 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6170 { 6171 const PetscInt np = *numPoints; 6172 PetscInt pStart, pEnd, p, q; 6173 6174 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6175 for (p = 0, q = 0; p < np; ++p) { 6176 const PetscInt r = points[p * 2]; 6177 if ((r >= pStart) && (r < pEnd)) { 6178 points[q * 2] = r; 6179 points[q * 2 + 1] = points[p * 2 + 1]; 6180 ++q; 6181 } 6182 } 6183 *numPoints = q; 6184 return PETSC_SUCCESS; 6185 } 6186 6187 /* Compressed closure does not apply closure permutation */ 6188 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6189 { 6190 const PetscInt *cla = NULL; 6191 PetscInt np, *pts = NULL; 6192 6193 PetscFunctionBeginHot; 6194 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6195 if (!ornt && *clPoints) { 6196 PetscInt dof, off; 6197 6198 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6199 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6200 PetscCall(ISGetIndices(*clPoints, &cla)); 6201 np = dof / 2; 6202 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6203 } else { 6204 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6205 PetscCall(CompressPoints_Private(section, &np, pts)); 6206 } 6207 *numPoints = np; 6208 *points = pts; 6209 *clp = cla; 6210 PetscFunctionReturn(PETSC_SUCCESS); 6211 } 6212 6213 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6214 { 6215 PetscFunctionBeginHot; 6216 if (!*clPoints) { 6217 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6218 } else { 6219 PetscCall(ISRestoreIndices(*clPoints, clp)); 6220 } 6221 *numPoints = 0; 6222 *points = NULL; 6223 *clSec = NULL; 6224 *clPoints = NULL; 6225 *clp = NULL; 6226 PetscFunctionReturn(PETSC_SUCCESS); 6227 } 6228 6229 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6230 { 6231 PetscInt offset = 0, p; 6232 const PetscInt **perms = NULL; 6233 const PetscScalar **flips = NULL; 6234 6235 PetscFunctionBeginHot; 6236 *size = 0; 6237 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6238 for (p = 0; p < numPoints; p++) { 6239 const PetscInt point = points[2 * p]; 6240 const PetscInt *perm = perms ? perms[p] : NULL; 6241 const PetscScalar *flip = flips ? flips[p] : NULL; 6242 PetscInt dof, off, d; 6243 const PetscScalar *varr; 6244 6245 PetscCall(PetscSectionGetDof(section, point, &dof)); 6246 PetscCall(PetscSectionGetOffset(section, point, &off)); 6247 varr = PetscSafePointerPlusOffset(vArray, off); 6248 if (clperm) { 6249 if (perm) { 6250 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6251 } else { 6252 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6253 } 6254 if (flip) { 6255 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6256 } 6257 } else { 6258 if (perm) { 6259 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6260 } else { 6261 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6262 } 6263 if (flip) { 6264 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6265 } 6266 } 6267 offset += dof; 6268 } 6269 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6270 *size = offset; 6271 PetscFunctionReturn(PETSC_SUCCESS); 6272 } 6273 6274 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[]) 6275 { 6276 PetscInt offset = 0, f; 6277 6278 PetscFunctionBeginHot; 6279 *size = 0; 6280 for (f = 0; f < numFields; ++f) { 6281 PetscInt p; 6282 const PetscInt **perms = NULL; 6283 const PetscScalar **flips = NULL; 6284 6285 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6286 for (p = 0; p < numPoints; p++) { 6287 const PetscInt point = points[2 * p]; 6288 PetscInt fdof, foff, b; 6289 const PetscScalar *varr; 6290 const PetscInt *perm = perms ? perms[p] : NULL; 6291 const PetscScalar *flip = flips ? flips[p] : NULL; 6292 6293 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6294 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6295 varr = &vArray[foff]; 6296 if (clperm) { 6297 if (perm) { 6298 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6299 } else { 6300 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6301 } 6302 if (flip) { 6303 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6304 } 6305 } else { 6306 if (perm) { 6307 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6308 } else { 6309 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6310 } 6311 if (flip) { 6312 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6313 } 6314 } 6315 offset += fdof; 6316 } 6317 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6318 } 6319 *size = offset; 6320 PetscFunctionReturn(PETSC_SUCCESS); 6321 } 6322 6323 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6324 { 6325 PetscSection clSection; 6326 IS clPoints; 6327 PetscInt *points = NULL; 6328 const PetscInt *clp, *perm = NULL; 6329 PetscInt depth, numFields, numPoints, asize; 6330 6331 PetscFunctionBeginHot; 6332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6333 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6334 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6335 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6336 PetscCall(DMPlexGetDepth(dm, &depth)); 6337 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6338 if (depth == 1 && numFields < 2) { 6339 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6340 PetscFunctionReturn(PETSC_SUCCESS); 6341 } 6342 /* Get points */ 6343 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6344 /* Get sizes */ 6345 asize = 0; 6346 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6347 PetscInt dof; 6348 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6349 asize += dof; 6350 } 6351 if (values) { 6352 const PetscScalar *vArray; 6353 PetscInt size; 6354 6355 if (*values) { 6356 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); 6357 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6358 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6359 PetscCall(VecGetArrayRead(v, &vArray)); 6360 /* Get values */ 6361 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6362 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6363 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6364 /* Cleanup array */ 6365 PetscCall(VecRestoreArrayRead(v, &vArray)); 6366 } 6367 if (csize) *csize = asize; 6368 /* Cleanup points */ 6369 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6370 PetscFunctionReturn(PETSC_SUCCESS); 6371 } 6372 6373 /*@C 6374 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6375 6376 Not collective 6377 6378 Input Parameters: 6379 + dm - The `DM` 6380 . section - The section describing the layout in `v`, or `NULL` to use the default section 6381 . v - The local vector 6382 - point - The point in the `DM` 6383 6384 Input/Output Parameters: 6385 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6386 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6387 if the user provided `NULL`, it is a borrowed array and should not be freed 6388 6389 Level: intermediate 6390 6391 Notes: 6392 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6393 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6394 assembly function, and a user may already have allocated storage for this operation. 6395 6396 A typical use could be 6397 .vb 6398 values = NULL; 6399 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6400 for (cl = 0; cl < clSize; ++cl) { 6401 <Compute on closure> 6402 } 6403 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6404 .ve 6405 or 6406 .vb 6407 PetscMalloc1(clMaxSize, &values); 6408 for (p = pStart; p < pEnd; ++p) { 6409 clSize = clMaxSize; 6410 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6411 for (cl = 0; cl < clSize; ++cl) { 6412 <Compute on closure> 6413 } 6414 } 6415 PetscFree(values); 6416 .ve 6417 6418 Fortran Notes: 6419 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6420 6421 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6422 @*/ 6423 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6424 { 6425 PetscFunctionBeginHot; 6426 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6427 PetscFunctionReturn(PETSC_SUCCESS); 6428 } 6429 6430 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6431 { 6432 DMLabel depthLabel; 6433 PetscSection clSection; 6434 IS clPoints; 6435 PetscScalar *array; 6436 const PetscScalar *vArray; 6437 PetscInt *points = NULL; 6438 const PetscInt *clp, *perm = NULL; 6439 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6440 6441 PetscFunctionBeginHot; 6442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6443 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6444 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6445 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6446 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6447 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6448 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6449 if (mdepth == 1 && numFields < 2) { 6450 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6451 PetscFunctionReturn(PETSC_SUCCESS); 6452 } 6453 /* Get points */ 6454 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6455 for (clsize = 0, p = 0; p < Np; p++) { 6456 PetscInt dof; 6457 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6458 clsize += dof; 6459 } 6460 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6461 /* Filter points */ 6462 for (p = 0; p < numPoints * 2; p += 2) { 6463 PetscInt dep; 6464 6465 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6466 if (dep != depth) continue; 6467 points[Np * 2 + 0] = points[p]; 6468 points[Np * 2 + 1] = points[p + 1]; 6469 ++Np; 6470 } 6471 /* Get array */ 6472 if (!values || !*values) { 6473 PetscInt asize = 0, dof; 6474 6475 for (p = 0; p < Np * 2; p += 2) { 6476 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6477 asize += dof; 6478 } 6479 if (!values) { 6480 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6481 if (csize) *csize = asize; 6482 PetscFunctionReturn(PETSC_SUCCESS); 6483 } 6484 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6485 } else { 6486 array = *values; 6487 } 6488 PetscCall(VecGetArrayRead(v, &vArray)); 6489 /* Get values */ 6490 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6491 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6492 /* Cleanup points */ 6493 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6494 /* Cleanup array */ 6495 PetscCall(VecRestoreArrayRead(v, &vArray)); 6496 if (!*values) { 6497 if (csize) *csize = size; 6498 *values = array; 6499 } else { 6500 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6501 *csize = size; 6502 } 6503 PetscFunctionReturn(PETSC_SUCCESS); 6504 } 6505 6506 /*@C 6507 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6508 6509 Not collective 6510 6511 Input Parameters: 6512 + dm - The `DM` 6513 . section - The section describing the layout in `v`, or `NULL` to use the default section 6514 . v - The local vector 6515 . point - The point in the `DM` 6516 . csize - The number of values in the closure, or `NULL` 6517 - values - The array of values, which is a borrowed array and should not be freed 6518 6519 Level: intermediate 6520 6521 Note: 6522 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6523 6524 Fortran Notes: 6525 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6526 6527 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6528 @*/ 6529 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6530 { 6531 PetscInt size = 0; 6532 6533 PetscFunctionBegin; 6534 /* Should work without recalculating size */ 6535 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6536 *values = NULL; 6537 PetscFunctionReturn(PETSC_SUCCESS); 6538 } 6539 6540 static inline void add(PetscScalar *x, PetscScalar y) 6541 { 6542 *x += y; 6543 } 6544 static inline void insert(PetscScalar *x, PetscScalar y) 6545 { 6546 *x = y; 6547 } 6548 6549 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[]) 6550 { 6551 PetscInt cdof; /* The number of constraints on this point */ 6552 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6553 PetscScalar *a; 6554 PetscInt off, cind = 0, k; 6555 6556 PetscFunctionBegin; 6557 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6558 PetscCall(PetscSectionGetOffset(section, point, &off)); 6559 a = &array[off]; 6560 if (!cdof || setBC) { 6561 if (clperm) { 6562 if (perm) { 6563 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6564 } else { 6565 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6566 } 6567 } else { 6568 if (perm) { 6569 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6570 } else { 6571 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6572 } 6573 } 6574 } else { 6575 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6576 if (clperm) { 6577 if (perm) { 6578 for (k = 0; k < dof; ++k) { 6579 if ((cind < cdof) && (k == cdofs[cind])) { 6580 ++cind; 6581 continue; 6582 } 6583 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6584 } 6585 } else { 6586 for (k = 0; k < dof; ++k) { 6587 if ((cind < cdof) && (k == cdofs[cind])) { 6588 ++cind; 6589 continue; 6590 } 6591 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6592 } 6593 } 6594 } else { 6595 if (perm) { 6596 for (k = 0; k < dof; ++k) { 6597 if ((cind < cdof) && (k == cdofs[cind])) { 6598 ++cind; 6599 continue; 6600 } 6601 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6602 } 6603 } else { 6604 for (k = 0; k < dof; ++k) { 6605 if ((cind < cdof) && (k == cdofs[cind])) { 6606 ++cind; 6607 continue; 6608 } 6609 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6610 } 6611 } 6612 } 6613 } 6614 PetscFunctionReturn(PETSC_SUCCESS); 6615 } 6616 6617 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[]) 6618 { 6619 PetscInt cdof; /* The number of constraints on this point */ 6620 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6621 PetscScalar *a; 6622 PetscInt off, cind = 0, k; 6623 6624 PetscFunctionBegin; 6625 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6626 PetscCall(PetscSectionGetOffset(section, point, &off)); 6627 a = &array[off]; 6628 if (cdof) { 6629 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6630 if (clperm) { 6631 if (perm) { 6632 for (k = 0; k < dof; ++k) { 6633 if ((cind < cdof) && (k == cdofs[cind])) { 6634 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6635 cind++; 6636 } 6637 } 6638 } else { 6639 for (k = 0; k < dof; ++k) { 6640 if ((cind < cdof) && (k == cdofs[cind])) { 6641 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6642 cind++; 6643 } 6644 } 6645 } 6646 } else { 6647 if (perm) { 6648 for (k = 0; k < dof; ++k) { 6649 if ((cind < cdof) && (k == cdofs[cind])) { 6650 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6651 cind++; 6652 } 6653 } 6654 } else { 6655 for (k = 0; k < dof; ++k) { 6656 if ((cind < cdof) && (k == cdofs[cind])) { 6657 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6658 cind++; 6659 } 6660 } 6661 } 6662 } 6663 } 6664 PetscFunctionReturn(PETSC_SUCCESS); 6665 } 6666 6667 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[]) 6668 { 6669 PetscScalar *a; 6670 PetscInt fdof, foff, fcdof, foffset = *offset; 6671 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6672 PetscInt cind = 0, b; 6673 6674 PetscFunctionBegin; 6675 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6676 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6677 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6678 a = &array[foff]; 6679 if (!fcdof || setBC) { 6680 if (clperm) { 6681 if (perm) { 6682 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6683 } else { 6684 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6685 } 6686 } else { 6687 if (perm) { 6688 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6689 } else { 6690 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6691 } 6692 } 6693 } else { 6694 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6695 if (clperm) { 6696 if (perm) { 6697 for (b = 0; b < fdof; b++) { 6698 if ((cind < fcdof) && (b == fcdofs[cind])) { 6699 ++cind; 6700 continue; 6701 } 6702 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6703 } 6704 } else { 6705 for (b = 0; b < fdof; b++) { 6706 if ((cind < fcdof) && (b == fcdofs[cind])) { 6707 ++cind; 6708 continue; 6709 } 6710 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6711 } 6712 } 6713 } else { 6714 if (perm) { 6715 for (b = 0; b < fdof; b++) { 6716 if ((cind < fcdof) && (b == fcdofs[cind])) { 6717 ++cind; 6718 continue; 6719 } 6720 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6721 } 6722 } else { 6723 for (b = 0; b < fdof; b++) { 6724 if ((cind < fcdof) && (b == fcdofs[cind])) { 6725 ++cind; 6726 continue; 6727 } 6728 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6729 } 6730 } 6731 } 6732 } 6733 *offset += fdof; 6734 PetscFunctionReturn(PETSC_SUCCESS); 6735 } 6736 6737 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[]) 6738 { 6739 PetscScalar *a; 6740 PetscInt fdof, foff, fcdof, foffset = *offset; 6741 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6742 PetscInt Nc, cind = 0, ncind = 0, b; 6743 PetscBool ncSet, fcSet; 6744 6745 PetscFunctionBegin; 6746 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6747 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6748 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6749 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6750 a = &array[foff]; 6751 if (fcdof) { 6752 /* We just override fcdof and fcdofs with Ncc and comps */ 6753 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6754 if (clperm) { 6755 if (perm) { 6756 if (comps) { 6757 for (b = 0; b < fdof; b++) { 6758 ncSet = fcSet = PETSC_FALSE; 6759 if (b % Nc == comps[ncind]) { 6760 ncind = (ncind + 1) % Ncc; 6761 ncSet = PETSC_TRUE; 6762 } 6763 if ((cind < fcdof) && (b == fcdofs[cind])) { 6764 ++cind; 6765 fcSet = PETSC_TRUE; 6766 } 6767 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6768 } 6769 } else { 6770 for (b = 0; b < fdof; b++) { 6771 if ((cind < fcdof) && (b == fcdofs[cind])) { 6772 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6773 ++cind; 6774 } 6775 } 6776 } 6777 } else { 6778 if (comps) { 6779 for (b = 0; b < fdof; b++) { 6780 ncSet = fcSet = PETSC_FALSE; 6781 if (b % Nc == comps[ncind]) { 6782 ncind = (ncind + 1) % Ncc; 6783 ncSet = PETSC_TRUE; 6784 } 6785 if ((cind < fcdof) && (b == fcdofs[cind])) { 6786 ++cind; 6787 fcSet = PETSC_TRUE; 6788 } 6789 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6790 } 6791 } else { 6792 for (b = 0; b < fdof; b++) { 6793 if ((cind < fcdof) && (b == fcdofs[cind])) { 6794 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6795 ++cind; 6796 } 6797 } 6798 } 6799 } 6800 } else { 6801 if (perm) { 6802 if (comps) { 6803 for (b = 0; b < fdof; b++) { 6804 ncSet = fcSet = PETSC_FALSE; 6805 if (b % Nc == comps[ncind]) { 6806 ncind = (ncind + 1) % Ncc; 6807 ncSet = PETSC_TRUE; 6808 } 6809 if ((cind < fcdof) && (b == fcdofs[cind])) { 6810 ++cind; 6811 fcSet = PETSC_TRUE; 6812 } 6813 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6814 } 6815 } else { 6816 for (b = 0; b < fdof; b++) { 6817 if ((cind < fcdof) && (b == fcdofs[cind])) { 6818 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6819 ++cind; 6820 } 6821 } 6822 } 6823 } else { 6824 if (comps) { 6825 for (b = 0; b < fdof; b++) { 6826 ncSet = fcSet = PETSC_FALSE; 6827 if (b % Nc == comps[ncind]) { 6828 ncind = (ncind + 1) % Ncc; 6829 ncSet = PETSC_TRUE; 6830 } 6831 if ((cind < fcdof) && (b == fcdofs[cind])) { 6832 ++cind; 6833 fcSet = PETSC_TRUE; 6834 } 6835 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6836 } 6837 } else { 6838 for (b = 0; b < fdof; b++) { 6839 if ((cind < fcdof) && (b == fcdofs[cind])) { 6840 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6841 ++cind; 6842 } 6843 } 6844 } 6845 } 6846 } 6847 } 6848 *offset += fdof; 6849 PetscFunctionReturn(PETSC_SUCCESS); 6850 } 6851 6852 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6853 { 6854 PetscScalar *array; 6855 const PetscInt *cone, *coneO; 6856 PetscInt pStart, pEnd, p, numPoints, off, dof; 6857 6858 PetscFunctionBeginHot; 6859 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6860 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6861 PetscCall(DMPlexGetCone(dm, point, &cone)); 6862 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6863 PetscCall(VecGetArray(v, &array)); 6864 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6865 const PetscInt cp = !p ? point : cone[p - 1]; 6866 const PetscInt o = !p ? 0 : coneO[p - 1]; 6867 6868 if ((cp < pStart) || (cp >= pEnd)) { 6869 dof = 0; 6870 continue; 6871 } 6872 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6873 /* ADD_VALUES */ 6874 { 6875 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6876 PetscScalar *a; 6877 PetscInt cdof, coff, cind = 0, k; 6878 6879 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6880 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6881 a = &array[coff]; 6882 if (!cdof) { 6883 if (o >= 0) { 6884 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6885 } else { 6886 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6887 } 6888 } else { 6889 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6890 if (o >= 0) { 6891 for (k = 0; k < dof; ++k) { 6892 if ((cind < cdof) && (k == cdofs[cind])) { 6893 ++cind; 6894 continue; 6895 } 6896 a[k] += values[off + k]; 6897 } 6898 } else { 6899 for (k = 0; k < dof; ++k) { 6900 if ((cind < cdof) && (k == cdofs[cind])) { 6901 ++cind; 6902 continue; 6903 } 6904 a[k] += values[off + dof - k - 1]; 6905 } 6906 } 6907 } 6908 } 6909 } 6910 PetscCall(VecRestoreArray(v, &array)); 6911 PetscFunctionReturn(PETSC_SUCCESS); 6912 } 6913 6914 /*@C 6915 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6916 6917 Not collective 6918 6919 Input Parameters: 6920 + dm - The `DM` 6921 . section - The section describing the layout in `v`, or `NULL` to use the default section 6922 . v - The local vector 6923 . point - The point in the `DM` 6924 . values - The array of values 6925 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6926 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6927 6928 Level: intermediate 6929 6930 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6931 @*/ 6932 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6933 { 6934 PetscSection clSection; 6935 IS clPoints; 6936 PetscScalar *array; 6937 PetscInt *points = NULL; 6938 const PetscInt *clp, *clperm = NULL; 6939 PetscInt depth, numFields, numPoints, p, clsize; 6940 6941 PetscFunctionBeginHot; 6942 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6943 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6944 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6945 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6946 PetscCall(DMPlexGetDepth(dm, &depth)); 6947 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6948 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6949 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6950 PetscFunctionReturn(PETSC_SUCCESS); 6951 } 6952 /* Get points */ 6953 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6954 for (clsize = 0, p = 0; p < numPoints; p++) { 6955 PetscInt dof; 6956 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6957 clsize += dof; 6958 } 6959 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6960 /* Get array */ 6961 PetscCall(VecGetArray(v, &array)); 6962 /* Get values */ 6963 if (numFields > 0) { 6964 PetscInt offset = 0, f; 6965 for (f = 0; f < numFields; ++f) { 6966 const PetscInt **perms = NULL; 6967 const PetscScalar **flips = NULL; 6968 6969 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6970 switch (mode) { 6971 case INSERT_VALUES: 6972 for (p = 0; p < numPoints; p++) { 6973 const PetscInt point = points[2 * p]; 6974 const PetscInt *perm = perms ? perms[p] : NULL; 6975 const PetscScalar *flip = flips ? flips[p] : NULL; 6976 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6977 } 6978 break; 6979 case INSERT_ALL_VALUES: 6980 for (p = 0; p < numPoints; p++) { 6981 const PetscInt point = points[2 * p]; 6982 const PetscInt *perm = perms ? perms[p] : NULL; 6983 const PetscScalar *flip = flips ? flips[p] : NULL; 6984 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6985 } 6986 break; 6987 case INSERT_BC_VALUES: 6988 for (p = 0; p < numPoints; p++) { 6989 const PetscInt point = points[2 * p]; 6990 const PetscInt *perm = perms ? perms[p] : NULL; 6991 const PetscScalar *flip = flips ? flips[p] : NULL; 6992 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6993 } 6994 break; 6995 case ADD_VALUES: 6996 for (p = 0; p < numPoints; p++) { 6997 const PetscInt point = points[2 * p]; 6998 const PetscInt *perm = perms ? perms[p] : NULL; 6999 const PetscScalar *flip = flips ? flips[p] : NULL; 7000 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7001 } 7002 break; 7003 case ADD_ALL_VALUES: 7004 for (p = 0; p < numPoints; p++) { 7005 const PetscInt point = points[2 * p]; 7006 const PetscInt *perm = perms ? perms[p] : NULL; 7007 const PetscScalar *flip = flips ? flips[p] : NULL; 7008 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7009 } 7010 break; 7011 case ADD_BC_VALUES: 7012 for (p = 0; p < numPoints; p++) { 7013 const PetscInt point = points[2 * p]; 7014 const PetscInt *perm = perms ? perms[p] : NULL; 7015 const PetscScalar *flip = flips ? flips[p] : NULL; 7016 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7017 } 7018 break; 7019 default: 7020 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7021 } 7022 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7023 } 7024 } else { 7025 PetscInt dof, off; 7026 const PetscInt **perms = NULL; 7027 const PetscScalar **flips = NULL; 7028 7029 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7030 switch (mode) { 7031 case INSERT_VALUES: 7032 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7033 const PetscInt point = points[2 * p]; 7034 const PetscInt *perm = perms ? perms[p] : NULL; 7035 const PetscScalar *flip = flips ? flips[p] : NULL; 7036 PetscCall(PetscSectionGetDof(section, point, &dof)); 7037 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7038 } 7039 break; 7040 case INSERT_ALL_VALUES: 7041 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7042 const PetscInt point = points[2 * p]; 7043 const PetscInt *perm = perms ? perms[p] : NULL; 7044 const PetscScalar *flip = flips ? flips[p] : NULL; 7045 PetscCall(PetscSectionGetDof(section, point, &dof)); 7046 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7047 } 7048 break; 7049 case INSERT_BC_VALUES: 7050 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7051 const PetscInt point = points[2 * p]; 7052 const PetscInt *perm = perms ? perms[p] : NULL; 7053 const PetscScalar *flip = flips ? flips[p] : NULL; 7054 PetscCall(PetscSectionGetDof(section, point, &dof)); 7055 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7056 } 7057 break; 7058 case ADD_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, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7065 } 7066 break; 7067 case ADD_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, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7074 } 7075 break; 7076 case ADD_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, add, perm, flip, clperm, values, off, array)); 7083 } 7084 break; 7085 default: 7086 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7087 } 7088 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7089 } 7090 /* Cleanup points */ 7091 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7092 /* Cleanup array */ 7093 PetscCall(VecRestoreArray(v, &array)); 7094 PetscFunctionReturn(PETSC_SUCCESS); 7095 } 7096 7097 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7098 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7099 { 7100 PetscFunctionBegin; 7101 *contains = PETSC_TRUE; 7102 if (label) { 7103 PetscInt fdof; 7104 7105 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7106 if (!*contains) { 7107 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7108 *offset += fdof; 7109 PetscFunctionReturn(PETSC_SUCCESS); 7110 } 7111 } 7112 PetscFunctionReturn(PETSC_SUCCESS); 7113 } 7114 7115 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7116 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) 7117 { 7118 PetscSection clSection; 7119 IS clPoints; 7120 PetscScalar *array; 7121 PetscInt *points = NULL; 7122 const PetscInt *clp; 7123 PetscInt numFields, numPoints, p; 7124 PetscInt offset = 0, f; 7125 7126 PetscFunctionBeginHot; 7127 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7128 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7129 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7130 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7131 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7132 /* Get points */ 7133 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7134 /* Get array */ 7135 PetscCall(VecGetArray(v, &array)); 7136 /* Get values */ 7137 for (f = 0; f < numFields; ++f) { 7138 const PetscInt **perms = NULL; 7139 const PetscScalar **flips = NULL; 7140 PetscBool contains; 7141 7142 if (!fieldActive[f]) { 7143 for (p = 0; p < numPoints * 2; p += 2) { 7144 PetscInt fdof; 7145 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7146 offset += fdof; 7147 } 7148 continue; 7149 } 7150 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7151 switch (mode) { 7152 case INSERT_VALUES: 7153 for (p = 0; p < numPoints; p++) { 7154 const PetscInt point = points[2 * p]; 7155 const PetscInt *perm = perms ? perms[p] : NULL; 7156 const PetscScalar *flip = flips ? flips[p] : NULL; 7157 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7158 if (!contains) continue; 7159 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7160 } 7161 break; 7162 case INSERT_ALL_VALUES: 7163 for (p = 0; p < numPoints; p++) { 7164 const PetscInt point = points[2 * p]; 7165 const PetscInt *perm = perms ? perms[p] : NULL; 7166 const PetscScalar *flip = flips ? flips[p] : NULL; 7167 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7168 if (!contains) continue; 7169 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7170 } 7171 break; 7172 case INSERT_BC_VALUES: 7173 for (p = 0; p < numPoints; p++) { 7174 const PetscInt point = points[2 * p]; 7175 const PetscInt *perm = perms ? perms[p] : NULL; 7176 const PetscScalar *flip = flips ? flips[p] : NULL; 7177 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7178 if (!contains) continue; 7179 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7180 } 7181 break; 7182 case ADD_VALUES: 7183 for (p = 0; p < numPoints; p++) { 7184 const PetscInt point = points[2 * p]; 7185 const PetscInt *perm = perms ? perms[p] : NULL; 7186 const PetscScalar *flip = flips ? flips[p] : NULL; 7187 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7188 if (!contains) continue; 7189 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7190 } 7191 break; 7192 case ADD_ALL_VALUES: 7193 for (p = 0; p < numPoints; p++) { 7194 const PetscInt point = points[2 * p]; 7195 const PetscInt *perm = perms ? perms[p] : NULL; 7196 const PetscScalar *flip = flips ? flips[p] : NULL; 7197 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7198 if (!contains) continue; 7199 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7200 } 7201 break; 7202 default: 7203 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7204 } 7205 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7206 } 7207 /* Cleanup points */ 7208 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7209 /* Cleanup array */ 7210 PetscCall(VecRestoreArray(v, &array)); 7211 PetscFunctionReturn(PETSC_SUCCESS); 7212 } 7213 7214 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7215 { 7216 PetscMPIInt rank; 7217 PetscInt i, j; 7218 7219 PetscFunctionBegin; 7220 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7221 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7222 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7223 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7224 numCIndices = numCIndices ? numCIndices : numRIndices; 7225 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7226 for (i = 0; i < numRIndices; i++) { 7227 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7228 for (j = 0; j < numCIndices; j++) { 7229 #if defined(PETSC_USE_COMPLEX) 7230 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7231 #else 7232 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7233 #endif 7234 } 7235 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7236 } 7237 PetscFunctionReturn(PETSC_SUCCESS); 7238 } 7239 7240 /* 7241 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7242 7243 Input Parameters: 7244 + section - The section for this data layout 7245 . islocal - Is the section (and thus indices being requested) local or global? 7246 . point - The point contributing dofs with these indices 7247 . off - The global offset of this point 7248 . loff - The local offset of each field 7249 . setBC - The flag determining whether to include indices of boundary values 7250 . perm - A permutation of the dofs on this point, or NULL 7251 - indperm - A permutation of the entire indices array, or NULL 7252 7253 Output Parameter: 7254 . indices - Indices for dofs on this point 7255 7256 Level: developer 7257 7258 Note: The indices could be local or global, depending on the value of 'off'. 7259 */ 7260 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7261 { 7262 PetscInt dof; /* The number of unknowns on this point */ 7263 PetscInt cdof; /* The number of constraints on this point */ 7264 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7265 PetscInt cind = 0, k; 7266 7267 PetscFunctionBegin; 7268 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7269 PetscCall(PetscSectionGetDof(section, point, &dof)); 7270 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7271 if (!cdof || setBC) { 7272 for (k = 0; k < dof; ++k) { 7273 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7274 const PetscInt ind = indperm ? indperm[preind] : preind; 7275 7276 indices[ind] = off + k; 7277 } 7278 } else { 7279 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7280 for (k = 0; k < dof; ++k) { 7281 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7282 const PetscInt ind = indperm ? indperm[preind] : preind; 7283 7284 if ((cind < cdof) && (k == cdofs[cind])) { 7285 /* Insert check for returning constrained indices */ 7286 indices[ind] = -(off + k + 1); 7287 ++cind; 7288 } else { 7289 indices[ind] = off + k - (islocal ? 0 : cind); 7290 } 7291 } 7292 } 7293 *loff += dof; 7294 PetscFunctionReturn(PETSC_SUCCESS); 7295 } 7296 7297 /* 7298 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7299 7300 Input Parameters: 7301 + section - a section (global or local) 7302 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7303 . point - point within section 7304 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7305 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7306 . setBC - identify constrained (boundary condition) points via involution. 7307 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7308 . permsoff - offset 7309 - indperm - index permutation 7310 7311 Output Parameter: 7312 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7313 . indices - array to hold indices (as defined by section) of each dof associated with point 7314 7315 Notes: 7316 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7317 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7318 in the local vector. 7319 7320 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7321 significant). It is invalid to call with a global section and setBC=true. 7322 7323 Developer Note: 7324 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7325 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7326 offset could be obtained from the section instead of passing it explicitly as we do now. 7327 7328 Example: 7329 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7330 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7331 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7332 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. 7333 7334 Level: developer 7335 */ 7336 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[]) 7337 { 7338 PetscInt numFields, foff, f; 7339 7340 PetscFunctionBegin; 7341 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7342 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7343 for (f = 0, foff = 0; f < numFields; ++f) { 7344 PetscInt fdof, cfdof; 7345 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7346 PetscInt cind = 0, b; 7347 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7348 7349 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7350 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7351 if (!cfdof || setBC) { 7352 for (b = 0; b < fdof; ++b) { 7353 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7354 const PetscInt ind = indperm ? indperm[preind] : preind; 7355 7356 indices[ind] = off + foff + b; 7357 } 7358 } else { 7359 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7360 for (b = 0; b < fdof; ++b) { 7361 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7362 const PetscInt ind = indperm ? indperm[preind] : preind; 7363 7364 if ((cind < cfdof) && (b == fcdofs[cind])) { 7365 indices[ind] = -(off + foff + b + 1); 7366 ++cind; 7367 } else { 7368 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7369 } 7370 } 7371 } 7372 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7373 foffs[f] += fdof; 7374 } 7375 PetscFunctionReturn(PETSC_SUCCESS); 7376 } 7377 7378 /* 7379 This version believes the globalSection offsets for each field, rather than just the point offset 7380 7381 . foffs - The offset into 'indices' for each field, since it is segregated by field 7382 7383 Notes: 7384 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7385 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7386 */ 7387 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7388 { 7389 PetscInt numFields, foff, f; 7390 7391 PetscFunctionBegin; 7392 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7393 for (f = 0; f < numFields; ++f) { 7394 PetscInt fdof, cfdof; 7395 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7396 PetscInt cind = 0, b; 7397 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7398 7399 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7400 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7401 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7402 if (!cfdof) { 7403 for (b = 0; b < fdof; ++b) { 7404 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7405 const PetscInt ind = indperm ? indperm[preind] : preind; 7406 7407 indices[ind] = foff + b; 7408 } 7409 } else { 7410 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7411 for (b = 0; b < fdof; ++b) { 7412 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7413 const PetscInt ind = indperm ? indperm[preind] : preind; 7414 7415 if ((cind < cfdof) && (b == fcdofs[cind])) { 7416 indices[ind] = -(foff + b + 1); 7417 ++cind; 7418 } else { 7419 indices[ind] = foff + b - cind; 7420 } 7421 } 7422 } 7423 foffs[f] += fdof; 7424 } 7425 PetscFunctionReturn(PETSC_SUCCESS); 7426 } 7427 7428 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) 7429 { 7430 Mat cMat; 7431 PetscSection aSec, cSec; 7432 IS aIS; 7433 PetscInt aStart = -1, aEnd = -1; 7434 const PetscInt *anchors; 7435 PetscInt numFields, f, p, q, newP = 0; 7436 PetscInt newNumPoints = 0, newNumIndices = 0; 7437 PetscInt *newPoints, *indices, *newIndices; 7438 PetscInt maxAnchor, maxDof; 7439 PetscInt newOffsets[32]; 7440 PetscInt *pointMatOffsets[32]; 7441 PetscInt *newPointOffsets[32]; 7442 PetscScalar *pointMat[32]; 7443 PetscScalar *newValues = NULL, *tmpValues; 7444 PetscBool anyConstrained = PETSC_FALSE; 7445 7446 PetscFunctionBegin; 7447 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7448 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7449 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7450 7451 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7452 /* if there are point-to-point constraints */ 7453 if (aSec) { 7454 PetscCall(PetscArrayzero(newOffsets, 32)); 7455 PetscCall(ISGetIndices(aIS, &anchors)); 7456 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7457 /* figure out how many points are going to be in the new element matrix 7458 * (we allow double counting, because it's all just going to be summed 7459 * into the global matrix anyway) */ 7460 for (p = 0; p < 2 * numPoints; p += 2) { 7461 PetscInt b = points[p]; 7462 PetscInt bDof = 0, bSecDof; 7463 7464 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7465 if (!bSecDof) continue; 7466 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7467 if (bDof) { 7468 /* this point is constrained */ 7469 /* it is going to be replaced by its anchors */ 7470 PetscInt bOff, q; 7471 7472 anyConstrained = PETSC_TRUE; 7473 newNumPoints += bDof; 7474 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7475 for (q = 0; q < bDof; q++) { 7476 PetscInt a = anchors[bOff + q]; 7477 PetscInt aDof; 7478 7479 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7480 newNumIndices += aDof; 7481 for (f = 0; f < numFields; ++f) { 7482 PetscInt fDof; 7483 7484 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7485 newOffsets[f + 1] += fDof; 7486 } 7487 } 7488 } else { 7489 /* this point is not constrained */ 7490 newNumPoints++; 7491 newNumIndices += bSecDof; 7492 for (f = 0; f < numFields; ++f) { 7493 PetscInt fDof; 7494 7495 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7496 newOffsets[f + 1] += fDof; 7497 } 7498 } 7499 } 7500 } 7501 if (!anyConstrained) { 7502 if (outNumPoints) *outNumPoints = 0; 7503 if (outNumIndices) *outNumIndices = 0; 7504 if (outPoints) *outPoints = NULL; 7505 if (outValues) *outValues = NULL; 7506 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7507 PetscFunctionReturn(PETSC_SUCCESS); 7508 } 7509 7510 if (outNumPoints) *outNumPoints = newNumPoints; 7511 if (outNumIndices) *outNumIndices = newNumIndices; 7512 7513 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7514 7515 if (!outPoints && !outValues) { 7516 if (offsets) { 7517 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7518 } 7519 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7520 PetscFunctionReturn(PETSC_SUCCESS); 7521 } 7522 7523 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7524 7525 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7526 7527 /* workspaces */ 7528 if (numFields) { 7529 for (f = 0; f < numFields; f++) { 7530 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7531 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7532 } 7533 } else { 7534 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7535 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7536 } 7537 7538 /* get workspaces for the point-to-point matrices */ 7539 if (numFields) { 7540 PetscInt totalOffset, totalMatOffset; 7541 7542 for (p = 0; p < numPoints; p++) { 7543 PetscInt b = points[2 * p]; 7544 PetscInt bDof = 0, bSecDof; 7545 7546 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7547 if (!bSecDof) { 7548 for (f = 0; f < numFields; f++) { 7549 newPointOffsets[f][p + 1] = 0; 7550 pointMatOffsets[f][p + 1] = 0; 7551 } 7552 continue; 7553 } 7554 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7555 if (bDof) { 7556 for (f = 0; f < numFields; f++) { 7557 PetscInt fDof, q, bOff, allFDof = 0; 7558 7559 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7560 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7561 for (q = 0; q < bDof; q++) { 7562 PetscInt a = anchors[bOff + q]; 7563 PetscInt aFDof; 7564 7565 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7566 allFDof += aFDof; 7567 } 7568 newPointOffsets[f][p + 1] = allFDof; 7569 pointMatOffsets[f][p + 1] = fDof * allFDof; 7570 } 7571 } else { 7572 for (f = 0; f < numFields; f++) { 7573 PetscInt fDof; 7574 7575 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7576 newPointOffsets[f][p + 1] = fDof; 7577 pointMatOffsets[f][p + 1] = 0; 7578 } 7579 } 7580 } 7581 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7582 newPointOffsets[f][0] = totalOffset; 7583 pointMatOffsets[f][0] = totalMatOffset; 7584 for (p = 0; p < numPoints; p++) { 7585 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7586 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7587 } 7588 totalOffset = newPointOffsets[f][numPoints]; 7589 totalMatOffset = pointMatOffsets[f][numPoints]; 7590 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7591 } 7592 } else { 7593 for (p = 0; p < numPoints; p++) { 7594 PetscInt b = points[2 * p]; 7595 PetscInt bDof = 0, bSecDof; 7596 7597 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7598 if (!bSecDof) { 7599 newPointOffsets[0][p + 1] = 0; 7600 pointMatOffsets[0][p + 1] = 0; 7601 continue; 7602 } 7603 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7604 if (bDof) { 7605 PetscInt bOff, q, allDof = 0; 7606 7607 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7608 for (q = 0; q < bDof; q++) { 7609 PetscInt a = anchors[bOff + q], aDof; 7610 7611 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7612 allDof += aDof; 7613 } 7614 newPointOffsets[0][p + 1] = allDof; 7615 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7616 } else { 7617 newPointOffsets[0][p + 1] = bSecDof; 7618 pointMatOffsets[0][p + 1] = 0; 7619 } 7620 } 7621 newPointOffsets[0][0] = 0; 7622 pointMatOffsets[0][0] = 0; 7623 for (p = 0; p < numPoints; p++) { 7624 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7625 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7626 } 7627 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7628 } 7629 7630 /* output arrays */ 7631 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7632 7633 /* get the point-to-point matrices; construct newPoints */ 7634 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7635 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7636 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7637 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7638 if (numFields) { 7639 for (p = 0, newP = 0; p < numPoints; p++) { 7640 PetscInt b = points[2 * p]; 7641 PetscInt o = points[2 * p + 1]; 7642 PetscInt bDof = 0, bSecDof; 7643 7644 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7645 if (!bSecDof) continue; 7646 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7647 if (bDof) { 7648 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7649 7650 fStart[0] = 0; 7651 fEnd[0] = 0; 7652 for (f = 0; f < numFields; f++) { 7653 PetscInt fDof; 7654 7655 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7656 fStart[f + 1] = fStart[f] + fDof; 7657 fEnd[f + 1] = fStart[f + 1]; 7658 } 7659 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7660 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7661 7662 fAnchorStart[0] = 0; 7663 fAnchorEnd[0] = 0; 7664 for (f = 0; f < numFields; f++) { 7665 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7666 7667 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7668 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7669 } 7670 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7671 for (q = 0; q < bDof; q++) { 7672 PetscInt a = anchors[bOff + q], aOff; 7673 7674 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7675 newPoints[2 * (newP + q)] = a; 7676 newPoints[2 * (newP + q) + 1] = 0; 7677 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7678 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7679 } 7680 newP += bDof; 7681 7682 if (outValues) { 7683 /* get the point-to-point submatrix */ 7684 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])); 7685 } 7686 } else { 7687 newPoints[2 * newP] = b; 7688 newPoints[2 * newP + 1] = o; 7689 newP++; 7690 } 7691 } 7692 } else { 7693 for (p = 0; p < numPoints; p++) { 7694 PetscInt b = points[2 * p]; 7695 PetscInt o = points[2 * p + 1]; 7696 PetscInt bDof = 0, bSecDof; 7697 7698 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7699 if (!bSecDof) continue; 7700 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7701 if (bDof) { 7702 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7703 7704 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7705 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7706 7707 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7708 for (q = 0; q < bDof; q++) { 7709 PetscInt a = anchors[bOff + q], aOff; 7710 7711 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7712 7713 newPoints[2 * (newP + q)] = a; 7714 newPoints[2 * (newP + q) + 1] = 0; 7715 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7716 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7717 } 7718 newP += bDof; 7719 7720 /* get the point-to-point submatrix */ 7721 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7722 } else { 7723 newPoints[2 * newP] = b; 7724 newPoints[2 * newP + 1] = o; 7725 newP++; 7726 } 7727 } 7728 } 7729 7730 if (outValues) { 7731 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7732 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7733 /* multiply constraints on the right */ 7734 if (numFields) { 7735 for (f = 0; f < numFields; f++) { 7736 PetscInt oldOff = offsets[f]; 7737 7738 for (p = 0; p < numPoints; p++) { 7739 PetscInt cStart = newPointOffsets[f][p]; 7740 PetscInt b = points[2 * p]; 7741 PetscInt c, r, k; 7742 PetscInt dof; 7743 7744 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7745 if (!dof) continue; 7746 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7747 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7748 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7749 7750 for (r = 0; r < numIndices; r++) { 7751 for (c = 0; c < nCols; c++) { 7752 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7753 } 7754 } 7755 } else { 7756 /* copy this column as is */ 7757 for (r = 0; r < numIndices; r++) { 7758 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7759 } 7760 } 7761 oldOff += dof; 7762 } 7763 } 7764 } else { 7765 PetscInt oldOff = 0; 7766 for (p = 0; p < numPoints; p++) { 7767 PetscInt cStart = newPointOffsets[0][p]; 7768 PetscInt b = points[2 * p]; 7769 PetscInt c, r, k; 7770 PetscInt dof; 7771 7772 PetscCall(PetscSectionGetDof(section, b, &dof)); 7773 if (!dof) continue; 7774 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7775 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7776 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7777 7778 for (r = 0; r < numIndices; r++) { 7779 for (c = 0; c < nCols; c++) { 7780 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7781 } 7782 } 7783 } else { 7784 /* copy this column as is */ 7785 for (r = 0; r < numIndices; r++) { 7786 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7787 } 7788 } 7789 oldOff += dof; 7790 } 7791 } 7792 7793 if (multiplyLeft) { 7794 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7795 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7796 /* multiply constraints transpose on the left */ 7797 if (numFields) { 7798 for (f = 0; f < numFields; f++) { 7799 PetscInt oldOff = offsets[f]; 7800 7801 for (p = 0; p < numPoints; p++) { 7802 PetscInt rStart = newPointOffsets[f][p]; 7803 PetscInt b = points[2 * p]; 7804 PetscInt c, r, k; 7805 PetscInt dof; 7806 7807 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7808 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7809 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7810 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7811 7812 for (r = 0; r < nRows; r++) { 7813 for (c = 0; c < newNumIndices; c++) { 7814 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7815 } 7816 } 7817 } else { 7818 /* copy this row as is */ 7819 for (r = 0; r < dof; r++) { 7820 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7821 } 7822 } 7823 oldOff += dof; 7824 } 7825 } 7826 } else { 7827 PetscInt oldOff = 0; 7828 7829 for (p = 0; p < numPoints; p++) { 7830 PetscInt rStart = newPointOffsets[0][p]; 7831 PetscInt b = points[2 * p]; 7832 PetscInt c, r, k; 7833 PetscInt dof; 7834 7835 PetscCall(PetscSectionGetDof(section, b, &dof)); 7836 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7837 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7838 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7839 7840 for (r = 0; r < nRows; r++) { 7841 for (c = 0; c < newNumIndices; c++) { 7842 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7843 } 7844 } 7845 } else { 7846 /* copy this row as is */ 7847 for (r = 0; r < dof; r++) { 7848 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7849 } 7850 } 7851 oldOff += dof; 7852 } 7853 } 7854 7855 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7856 } else { 7857 newValues = tmpValues; 7858 } 7859 } 7860 7861 /* clean up */ 7862 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7863 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7864 7865 if (numFields) { 7866 for (f = 0; f < numFields; f++) { 7867 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7868 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7869 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7870 } 7871 } else { 7872 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7873 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7874 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7875 } 7876 PetscCall(ISRestoreIndices(aIS, &anchors)); 7877 7878 /* output */ 7879 if (outPoints) { 7880 *outPoints = newPoints; 7881 } else { 7882 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7883 } 7884 if (outValues) *outValues = newValues; 7885 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7886 PetscFunctionReturn(PETSC_SUCCESS); 7887 } 7888 7889 /*@C 7890 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7891 7892 Not collective 7893 7894 Input Parameters: 7895 + dm - The `DM` 7896 . section - The `PetscSection` describing the points (a local section) 7897 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7898 . point - The point defining the closure 7899 - useClPerm - Use the closure point permutation if available 7900 7901 Output Parameters: 7902 + numIndices - The number of dof indices in the closure of point with the input sections 7903 . indices - The dof indices 7904 . outOffsets - Array to write the field offsets into, or `NULL` 7905 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7906 7907 Level: advanced 7908 7909 Notes: 7910 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7911 7912 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7913 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7914 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7915 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7916 indices (with the above semantics) are implied. 7917 7918 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7919 `PetscSection`, `DMGetGlobalSection()` 7920 @*/ 7921 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7922 { 7923 /* Closure ordering */ 7924 PetscSection clSection; 7925 IS clPoints; 7926 const PetscInt *clp; 7927 PetscInt *points; 7928 const PetscInt *clperm = NULL; 7929 /* Dof permutation and sign flips */ 7930 const PetscInt **perms[32] = {NULL}; 7931 const PetscScalar **flips[32] = {NULL}; 7932 PetscScalar *valCopy = NULL; 7933 /* Hanging node constraints */ 7934 PetscInt *pointsC = NULL; 7935 PetscScalar *valuesC = NULL; 7936 PetscInt NclC, NiC; 7937 7938 PetscInt *idx; 7939 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7940 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7941 7942 PetscFunctionBeginHot; 7943 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7944 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7945 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7946 if (numIndices) PetscAssertPointer(numIndices, 6); 7947 if (indices) PetscAssertPointer(indices, 7); 7948 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7949 if (values) PetscAssertPointer(values, 9); 7950 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7951 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7952 PetscCall(PetscArrayzero(offsets, 32)); 7953 /* 1) Get points in closure */ 7954 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7955 if (useClPerm) { 7956 PetscInt depth, clsize; 7957 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7958 for (clsize = 0, p = 0; p < Ncl; p++) { 7959 PetscInt dof; 7960 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7961 clsize += dof; 7962 } 7963 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7964 } 7965 /* 2) Get number of indices on these points and field offsets from section */ 7966 for (p = 0; p < Ncl * 2; p += 2) { 7967 PetscInt dof, fdof; 7968 7969 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7970 for (f = 0; f < Nf; ++f) { 7971 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7972 offsets[f + 1] += fdof; 7973 } 7974 Ni += dof; 7975 } 7976 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7977 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7978 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7979 for (f = 0; f < PetscMax(1, Nf); ++f) { 7980 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7981 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7982 /* may need to apply sign changes to the element matrix */ 7983 if (values && flips[f]) { 7984 PetscInt foffset = offsets[f]; 7985 7986 for (p = 0; p < Ncl; ++p) { 7987 PetscInt pnt = points[2 * p], fdof; 7988 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7989 7990 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7991 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7992 if (flip) { 7993 PetscInt i, j, k; 7994 7995 if (!valCopy) { 7996 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7997 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7998 *values = valCopy; 7999 } 8000 for (i = 0; i < fdof; ++i) { 8001 PetscScalar fval = flip[i]; 8002 8003 for (k = 0; k < Ni; ++k) { 8004 valCopy[Ni * (foffset + i) + k] *= fval; 8005 valCopy[Ni * k + (foffset + i)] *= fval; 8006 } 8007 } 8008 } 8009 foffset += fdof; 8010 } 8011 } 8012 } 8013 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8014 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 8015 if (NclC) { 8016 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8017 for (f = 0; f < PetscMax(1, Nf); ++f) { 8018 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8019 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8020 } 8021 for (f = 0; f < PetscMax(1, Nf); ++f) { 8022 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8023 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8024 } 8025 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8026 Ncl = NclC; 8027 Ni = NiC; 8028 points = pointsC; 8029 if (values) *values = valuesC; 8030 } 8031 /* 5) Calculate indices */ 8032 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8033 if (Nf) { 8034 PetscInt idxOff; 8035 PetscBool useFieldOffsets; 8036 8037 if (outOffsets) { 8038 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8039 } 8040 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8041 if (useFieldOffsets) { 8042 for (p = 0; p < Ncl; ++p) { 8043 const PetscInt pnt = points[p * 2]; 8044 8045 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8046 } 8047 } else { 8048 for (p = 0; p < Ncl; ++p) { 8049 const PetscInt pnt = points[p * 2]; 8050 8051 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8052 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8053 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8054 * global section. */ 8055 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8056 } 8057 } 8058 } else { 8059 PetscInt off = 0, idxOff; 8060 8061 for (p = 0; p < Ncl; ++p) { 8062 const PetscInt pnt = points[p * 2]; 8063 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8064 8065 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8066 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8067 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8068 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8069 } 8070 } 8071 /* 6) Cleanup */ 8072 for (f = 0; f < PetscMax(1, Nf); ++f) { 8073 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8074 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8075 } 8076 if (NclC) { 8077 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8078 } else { 8079 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8080 } 8081 8082 if (numIndices) *numIndices = Ni; 8083 if (indices) *indices = idx; 8084 PetscFunctionReturn(PETSC_SUCCESS); 8085 } 8086 8087 /*@C 8088 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8089 8090 Not collective 8091 8092 Input Parameters: 8093 + dm - The `DM` 8094 . section - The `PetscSection` describing the points (a local section) 8095 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8096 . point - The point defining the closure 8097 - useClPerm - Use the closure point permutation if available 8098 8099 Output Parameters: 8100 + numIndices - The number of dof indices in the closure of point with the input sections 8101 . indices - The dof indices 8102 . outOffsets - Array to write the field offsets into, or `NULL` 8103 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8104 8105 Level: advanced 8106 8107 Notes: 8108 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8109 8110 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8111 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8112 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8113 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8114 indices (with the above semantics) are implied. 8115 8116 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8117 @*/ 8118 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8119 { 8120 PetscFunctionBegin; 8121 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8122 PetscAssertPointer(indices, 7); 8123 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8124 PetscFunctionReturn(PETSC_SUCCESS); 8125 } 8126 8127 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8128 { 8129 DM_Plex *mesh = (DM_Plex *)dm->data; 8130 PetscInt *indices; 8131 PetscInt numIndices; 8132 const PetscScalar *valuesOrig = values; 8133 PetscErrorCode ierr; 8134 8135 PetscFunctionBegin; 8136 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8137 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8138 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8139 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8140 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8141 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8142 8143 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8144 8145 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8146 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8147 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8148 if (ierr) { 8149 PetscMPIInt rank; 8150 8151 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8152 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8153 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8154 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8155 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8156 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8157 } 8158 if (mesh->printFEM > 1) { 8159 PetscInt i; 8160 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8161 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8162 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8163 } 8164 8165 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8166 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8167 PetscFunctionReturn(PETSC_SUCCESS); 8168 } 8169 8170 /*@C 8171 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8172 8173 Not collective 8174 8175 Input Parameters: 8176 + dm - The `DM` 8177 . section - The section describing the layout in `v`, or `NULL` to use the default section 8178 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8179 . A - The matrix 8180 . point - The point in the `DM` 8181 . values - The array of values 8182 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8183 8184 Level: intermediate 8185 8186 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8187 @*/ 8188 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8189 { 8190 PetscFunctionBegin; 8191 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8192 PetscFunctionReturn(PETSC_SUCCESS); 8193 } 8194 8195 /*@C 8196 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8197 8198 Not collective 8199 8200 Input Parameters: 8201 + dmRow - The `DM` for the row fields 8202 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8203 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8204 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8205 . dmCol - The `DM` for the column fields 8206 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8207 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8208 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8209 . A - The matrix 8210 . point - The point in the `DM` 8211 . values - The array of values 8212 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8213 8214 Level: intermediate 8215 8216 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8217 @*/ 8218 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) 8219 { 8220 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8221 PetscInt *indicesRow, *indicesCol; 8222 PetscInt numIndicesRow, numIndicesCol; 8223 const PetscScalar *valuesOrig = values; 8224 PetscErrorCode ierr; 8225 8226 PetscFunctionBegin; 8227 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8228 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8229 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8230 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8231 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8232 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8233 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8234 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8235 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8236 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8237 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8238 8239 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8240 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8241 8242 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8243 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8244 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8245 if (ierr) { 8246 PetscMPIInt rank; 8247 8248 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8249 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8250 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8251 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8252 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8253 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8254 } 8255 8256 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8257 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8258 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8259 PetscFunctionReturn(PETSC_SUCCESS); 8260 } 8261 8262 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8263 { 8264 DM_Plex *mesh = (DM_Plex *)dmf->data; 8265 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8266 PetscInt *cpoints = NULL; 8267 PetscInt *findices, *cindices; 8268 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8269 PetscInt foffsets[32], coffsets[32]; 8270 DMPolytopeType ct; 8271 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8272 PetscErrorCode ierr; 8273 8274 PetscFunctionBegin; 8275 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8276 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8277 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8278 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8279 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8280 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8281 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8282 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8283 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8284 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8285 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8286 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8287 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8288 PetscCall(PetscArrayzero(foffsets, 32)); 8289 PetscCall(PetscArrayzero(coffsets, 32)); 8290 /* Column indices */ 8291 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8292 maxFPoints = numCPoints; 8293 /* Compress out points not in the section */ 8294 /* TODO: Squeeze out points with 0 dof as well */ 8295 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8296 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8297 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8298 cpoints[q * 2] = cpoints[p]; 8299 cpoints[q * 2 + 1] = cpoints[p + 1]; 8300 ++q; 8301 } 8302 } 8303 numCPoints = q; 8304 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8305 PetscInt fdof; 8306 8307 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8308 if (!dof) continue; 8309 for (f = 0; f < numFields; ++f) { 8310 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8311 coffsets[f + 1] += fdof; 8312 } 8313 numCIndices += dof; 8314 } 8315 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8316 /* Row indices */ 8317 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8318 { 8319 DMPlexTransform tr; 8320 DMPolytopeType *rct; 8321 PetscInt *rsize, *rcone, *rornt, Nt; 8322 8323 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8324 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8325 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8326 numSubcells = rsize[Nt - 1]; 8327 PetscCall(DMPlexTransformDestroy(&tr)); 8328 } 8329 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8330 for (r = 0, q = 0; r < numSubcells; ++r) { 8331 /* TODO Map from coarse to fine cells */ 8332 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8333 /* Compress out points not in the section */ 8334 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8335 for (p = 0; p < numFPoints * 2; p += 2) { 8336 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8337 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8338 if (!dof) continue; 8339 for (s = 0; s < q; ++s) 8340 if (fpoints[p] == ftotpoints[s * 2]) break; 8341 if (s < q) continue; 8342 ftotpoints[q * 2] = fpoints[p]; 8343 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8344 ++q; 8345 } 8346 } 8347 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8348 } 8349 numFPoints = q; 8350 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8351 PetscInt fdof; 8352 8353 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8354 if (!dof) continue; 8355 for (f = 0; f < numFields; ++f) { 8356 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8357 foffsets[f + 1] += fdof; 8358 } 8359 numFIndices += dof; 8360 } 8361 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8362 8363 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8364 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8365 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8366 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8367 if (numFields) { 8368 const PetscInt **permsF[32] = {NULL}; 8369 const PetscInt **permsC[32] = {NULL}; 8370 8371 for (f = 0; f < numFields; f++) { 8372 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8373 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8374 } 8375 for (p = 0; p < numFPoints; p++) { 8376 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8377 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8378 } 8379 for (p = 0; p < numCPoints; p++) { 8380 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8381 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8382 } 8383 for (f = 0; f < numFields; f++) { 8384 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8385 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8386 } 8387 } else { 8388 const PetscInt **permsF = NULL; 8389 const PetscInt **permsC = NULL; 8390 8391 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8392 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8393 for (p = 0, off = 0; p < numFPoints; p++) { 8394 const PetscInt *perm = permsF ? permsF[p] : NULL; 8395 8396 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8397 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8398 } 8399 for (p = 0, off = 0; p < numCPoints; p++) { 8400 const PetscInt *perm = permsC ? permsC[p] : NULL; 8401 8402 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8403 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8404 } 8405 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8406 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8407 } 8408 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8409 /* TODO: flips */ 8410 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8411 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8412 if (ierr) { 8413 PetscMPIInt rank; 8414 8415 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8416 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8417 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8418 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8419 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8420 } 8421 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8422 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8423 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8424 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8425 PetscFunctionReturn(PETSC_SUCCESS); 8426 } 8427 8428 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8429 { 8430 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8431 PetscInt *cpoints = NULL; 8432 PetscInt foffsets[32], coffsets[32]; 8433 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8434 DMPolytopeType ct; 8435 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8436 8437 PetscFunctionBegin; 8438 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8439 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8440 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8441 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8442 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8443 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8444 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8445 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8446 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8447 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8448 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8449 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8450 PetscCall(PetscArrayzero(foffsets, 32)); 8451 PetscCall(PetscArrayzero(coffsets, 32)); 8452 /* Column indices */ 8453 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8454 maxFPoints = numCPoints; 8455 /* Compress out points not in the section */ 8456 /* TODO: Squeeze out points with 0 dof as well */ 8457 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8458 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8459 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8460 cpoints[q * 2] = cpoints[p]; 8461 cpoints[q * 2 + 1] = cpoints[p + 1]; 8462 ++q; 8463 } 8464 } 8465 numCPoints = q; 8466 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8467 PetscInt fdof; 8468 8469 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8470 if (!dof) continue; 8471 for (f = 0; f < numFields; ++f) { 8472 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8473 coffsets[f + 1] += fdof; 8474 } 8475 numCIndices += dof; 8476 } 8477 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8478 /* Row indices */ 8479 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8480 { 8481 DMPlexTransform tr; 8482 DMPolytopeType *rct; 8483 PetscInt *rsize, *rcone, *rornt, Nt; 8484 8485 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8486 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8487 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8488 numSubcells = rsize[Nt - 1]; 8489 PetscCall(DMPlexTransformDestroy(&tr)); 8490 } 8491 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8492 for (r = 0, q = 0; r < numSubcells; ++r) { 8493 /* TODO Map from coarse to fine cells */ 8494 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8495 /* Compress out points not in the section */ 8496 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8497 for (p = 0; p < numFPoints * 2; p += 2) { 8498 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8499 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8500 if (!dof) continue; 8501 for (s = 0; s < q; ++s) 8502 if (fpoints[p] == ftotpoints[s * 2]) break; 8503 if (s < q) continue; 8504 ftotpoints[q * 2] = fpoints[p]; 8505 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8506 ++q; 8507 } 8508 } 8509 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8510 } 8511 numFPoints = q; 8512 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8513 PetscInt fdof; 8514 8515 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8516 if (!dof) continue; 8517 for (f = 0; f < numFields; ++f) { 8518 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8519 foffsets[f + 1] += fdof; 8520 } 8521 numFIndices += dof; 8522 } 8523 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8524 8525 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8526 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8527 if (numFields) { 8528 const PetscInt **permsF[32] = {NULL}; 8529 const PetscInt **permsC[32] = {NULL}; 8530 8531 for (f = 0; f < numFields; f++) { 8532 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8533 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8534 } 8535 for (p = 0; p < numFPoints; p++) { 8536 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8537 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8538 } 8539 for (p = 0; p < numCPoints; p++) { 8540 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8541 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8542 } 8543 for (f = 0; f < numFields; f++) { 8544 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8545 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8546 } 8547 } else { 8548 const PetscInt **permsF = NULL; 8549 const PetscInt **permsC = NULL; 8550 8551 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8552 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8553 for (p = 0, off = 0; p < numFPoints; p++) { 8554 const PetscInt *perm = permsF ? permsF[p] : NULL; 8555 8556 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8557 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8558 } 8559 for (p = 0, off = 0; p < numCPoints; p++) { 8560 const PetscInt *perm = permsC ? permsC[p] : NULL; 8561 8562 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8563 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8564 } 8565 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8566 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8567 } 8568 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8569 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8570 PetscFunctionReturn(PETSC_SUCCESS); 8571 } 8572 8573 /*@C 8574 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8575 8576 Input Parameter: 8577 . dm - The `DMPLEX` object 8578 8579 Output Parameter: 8580 . cellHeight - The height of a cell 8581 8582 Level: developer 8583 8584 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8585 @*/ 8586 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8587 { 8588 DM_Plex *mesh = (DM_Plex *)dm->data; 8589 8590 PetscFunctionBegin; 8591 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8592 PetscAssertPointer(cellHeight, 2); 8593 *cellHeight = mesh->vtkCellHeight; 8594 PetscFunctionReturn(PETSC_SUCCESS); 8595 } 8596 8597 /*@C 8598 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8599 8600 Input Parameters: 8601 + dm - The `DMPLEX` object 8602 - cellHeight - The height of a cell 8603 8604 Level: developer 8605 8606 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8607 @*/ 8608 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8609 { 8610 DM_Plex *mesh = (DM_Plex *)dm->data; 8611 8612 PetscFunctionBegin; 8613 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8614 mesh->vtkCellHeight = cellHeight; 8615 PetscFunctionReturn(PETSC_SUCCESS); 8616 } 8617 8618 /*@ 8619 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8620 8621 Input Parameters: 8622 + dm - The `DMPLEX` object 8623 - ct - The `DMPolytopeType` of the cell 8624 8625 Output Parameters: 8626 + start - The first cell of this type, or `NULL` 8627 - end - The upper bound on this celltype, or `NULL` 8628 8629 Level: advanced 8630 8631 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8632 @*/ 8633 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8634 { 8635 DM_Plex *mesh = (DM_Plex *)dm->data; 8636 DMLabel label; 8637 PetscInt pStart, pEnd; 8638 8639 PetscFunctionBegin; 8640 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8641 if (start) { 8642 PetscAssertPointer(start, 3); 8643 *start = 0; 8644 } 8645 if (end) { 8646 PetscAssertPointer(end, 4); 8647 *end = 0; 8648 } 8649 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8650 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8651 if (mesh->tr) { 8652 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8653 } else { 8654 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8655 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8656 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8657 } 8658 PetscFunctionReturn(PETSC_SUCCESS); 8659 } 8660 8661 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8662 { 8663 PetscSection section, globalSection; 8664 PetscInt *numbers, p; 8665 8666 PetscFunctionBegin; 8667 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8668 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8669 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8670 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8671 PetscCall(PetscSectionSetUp(section)); 8672 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8673 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8674 for (p = pStart; p < pEnd; ++p) { 8675 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8676 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8677 else numbers[p - pStart] += shift; 8678 } 8679 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8680 if (globalSize) { 8681 PetscLayout layout; 8682 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8683 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8684 PetscCall(PetscLayoutDestroy(&layout)); 8685 } 8686 PetscCall(PetscSectionDestroy(§ion)); 8687 PetscCall(PetscSectionDestroy(&globalSection)); 8688 PetscFunctionReturn(PETSC_SUCCESS); 8689 } 8690 8691 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8692 { 8693 PetscInt cellHeight, cStart, cEnd; 8694 8695 PetscFunctionBegin; 8696 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8697 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8698 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8699 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8700 PetscFunctionReturn(PETSC_SUCCESS); 8701 } 8702 8703 /*@ 8704 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8705 8706 Input Parameter: 8707 . dm - The `DMPLEX` object 8708 8709 Output Parameter: 8710 . globalCellNumbers - Global cell numbers for all cells on this process 8711 8712 Level: developer 8713 8714 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8715 @*/ 8716 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8717 { 8718 DM_Plex *mesh = (DM_Plex *)dm->data; 8719 8720 PetscFunctionBegin; 8721 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8722 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8723 *globalCellNumbers = mesh->globalCellNumbers; 8724 PetscFunctionReturn(PETSC_SUCCESS); 8725 } 8726 8727 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8728 { 8729 PetscInt vStart, vEnd; 8730 8731 PetscFunctionBegin; 8732 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8733 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8734 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8735 PetscFunctionReturn(PETSC_SUCCESS); 8736 } 8737 8738 /*@ 8739 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8740 8741 Input Parameter: 8742 . dm - The `DMPLEX` object 8743 8744 Output Parameter: 8745 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8746 8747 Level: developer 8748 8749 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8750 @*/ 8751 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8752 { 8753 DM_Plex *mesh = (DM_Plex *)dm->data; 8754 8755 PetscFunctionBegin; 8756 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8757 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8758 *globalVertexNumbers = mesh->globalVertexNumbers; 8759 PetscFunctionReturn(PETSC_SUCCESS); 8760 } 8761 8762 /*@ 8763 DMPlexCreatePointNumbering - Create a global numbering for all points. 8764 8765 Collective 8766 8767 Input Parameter: 8768 . dm - The `DMPLEX` object 8769 8770 Output Parameter: 8771 . globalPointNumbers - Global numbers for all points on this process 8772 8773 Level: developer 8774 8775 Notes: 8776 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8777 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8778 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8779 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8780 8781 The partitioned mesh is 8782 ``` 8783 (2)--0--(3)--1--(4) (1)--0--(2) 8784 ``` 8785 and its global numbering is 8786 ``` 8787 (3)--0--(4)--1--(5)--2--(6) 8788 ``` 8789 Then the global numbering is provided as 8790 ``` 8791 [0] Number of indices in set 5 8792 [0] 0 0 8793 [0] 1 1 8794 [0] 2 3 8795 [0] 3 4 8796 [0] 4 -6 8797 [1] Number of indices in set 3 8798 [1] 0 2 8799 [1] 1 5 8800 [1] 2 6 8801 ``` 8802 8803 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8804 @*/ 8805 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8806 { 8807 IS nums[4]; 8808 PetscInt depths[4], gdepths[4], starts[4]; 8809 PetscInt depth, d, shift = 0; 8810 PetscBool empty = PETSC_FALSE; 8811 8812 PetscFunctionBegin; 8813 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8814 PetscCall(DMPlexGetDepth(dm, &depth)); 8815 // For unstratified meshes use dim instead of depth 8816 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8817 // If any stratum is empty, we must mark all empty 8818 for (d = 0; d <= depth; ++d) { 8819 PetscInt end; 8820 8821 depths[d] = depth - d; 8822 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8823 if (!(starts[d] - end)) empty = PETSC_TRUE; 8824 } 8825 if (empty) 8826 for (d = 0; d <= depth; ++d) { 8827 depths[d] = -1; 8828 starts[d] = -1; 8829 } 8830 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8831 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8832 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]); 8833 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8834 for (d = 0; d <= depth; ++d) { 8835 PetscInt pStart, pEnd, gsize; 8836 8837 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8838 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8839 shift += gsize; 8840 } 8841 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8842 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8843 PetscFunctionReturn(PETSC_SUCCESS); 8844 } 8845 8846 /*@ 8847 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8848 8849 Input Parameter: 8850 . dm - The `DMPLEX` object 8851 8852 Output Parameter: 8853 . ranks - The rank field 8854 8855 Options Database Key: 8856 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8857 8858 Level: intermediate 8859 8860 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8861 @*/ 8862 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8863 { 8864 DM rdm; 8865 PetscFE fe; 8866 PetscScalar *r; 8867 PetscMPIInt rank; 8868 DMPolytopeType ct; 8869 PetscInt dim, cStart, cEnd, c; 8870 PetscBool simplex; 8871 8872 PetscFunctionBeginUser; 8873 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8874 PetscAssertPointer(ranks, 2); 8875 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8876 PetscCall(DMClone(dm, &rdm)); 8877 PetscCall(DMGetDimension(rdm, &dim)); 8878 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8879 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8880 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8881 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8882 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8883 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8884 PetscCall(PetscFEDestroy(&fe)); 8885 PetscCall(DMCreateDS(rdm)); 8886 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8887 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8888 PetscCall(VecGetArray(*ranks, &r)); 8889 for (c = cStart; c < cEnd; ++c) { 8890 PetscScalar *lr; 8891 8892 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8893 if (lr) *lr = rank; 8894 } 8895 PetscCall(VecRestoreArray(*ranks, &r)); 8896 PetscCall(DMDestroy(&rdm)); 8897 PetscFunctionReturn(PETSC_SUCCESS); 8898 } 8899 8900 /*@ 8901 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8902 8903 Input Parameters: 8904 + dm - The `DMPLEX` 8905 - label - The `DMLabel` 8906 8907 Output Parameter: 8908 . val - The label value field 8909 8910 Options Database Key: 8911 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8912 8913 Level: intermediate 8914 8915 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8916 @*/ 8917 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8918 { 8919 DM rdm; 8920 PetscFE fe; 8921 PetscScalar *v; 8922 PetscInt dim, cStart, cEnd, c; 8923 8924 PetscFunctionBeginUser; 8925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8926 PetscAssertPointer(label, 2); 8927 PetscAssertPointer(val, 3); 8928 PetscCall(DMClone(dm, &rdm)); 8929 PetscCall(DMGetDimension(rdm, &dim)); 8930 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8931 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8932 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8933 PetscCall(PetscFEDestroy(&fe)); 8934 PetscCall(DMCreateDS(rdm)); 8935 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8936 PetscCall(DMCreateGlobalVector(rdm, val)); 8937 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8938 PetscCall(VecGetArray(*val, &v)); 8939 for (c = cStart; c < cEnd; ++c) { 8940 PetscScalar *lv; 8941 PetscInt cval; 8942 8943 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8944 PetscCall(DMLabelGetValue(label, c, &cval)); 8945 *lv = cval; 8946 } 8947 PetscCall(VecRestoreArray(*val, &v)); 8948 PetscCall(DMDestroy(&rdm)); 8949 PetscFunctionReturn(PETSC_SUCCESS); 8950 } 8951 8952 /*@ 8953 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8954 8955 Input Parameter: 8956 . dm - The `DMPLEX` object 8957 8958 Level: developer 8959 8960 Notes: 8961 This is a useful diagnostic when creating meshes programmatically. 8962 8963 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8964 8965 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8966 @*/ 8967 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8968 { 8969 PetscSection coneSection, supportSection; 8970 const PetscInt *cone, *support; 8971 PetscInt coneSize, c, supportSize, s; 8972 PetscInt pStart, pEnd, p, pp, csize, ssize; 8973 PetscBool storagecheck = PETSC_TRUE; 8974 8975 PetscFunctionBegin; 8976 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8977 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8978 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8979 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8980 /* Check that point p is found in the support of its cone points, and vice versa */ 8981 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8982 for (p = pStart; p < pEnd; ++p) { 8983 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8984 PetscCall(DMPlexGetCone(dm, p, &cone)); 8985 for (c = 0; c < coneSize; ++c) { 8986 PetscBool dup = PETSC_FALSE; 8987 PetscInt d; 8988 for (d = c - 1; d >= 0; --d) { 8989 if (cone[c] == cone[d]) { 8990 dup = PETSC_TRUE; 8991 break; 8992 } 8993 } 8994 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8995 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8996 for (s = 0; s < supportSize; ++s) { 8997 if (support[s] == p) break; 8998 } 8999 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9000 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9001 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9002 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9003 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9004 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9005 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9006 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]); 9007 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9008 } 9009 } 9010 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9011 if (p != pp) { 9012 storagecheck = PETSC_FALSE; 9013 continue; 9014 } 9015 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9016 PetscCall(DMPlexGetSupport(dm, p, &support)); 9017 for (s = 0; s < supportSize; ++s) { 9018 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9019 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9020 for (c = 0; c < coneSize; ++c) { 9021 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9022 if (cone[c] != pp) { 9023 c = 0; 9024 break; 9025 } 9026 if (cone[c] == p) break; 9027 } 9028 if (c >= coneSize) { 9029 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9030 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9031 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9032 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9033 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9034 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9035 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9036 } 9037 } 9038 } 9039 if (storagecheck) { 9040 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9041 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9042 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9043 } 9044 PetscFunctionReturn(PETSC_SUCCESS); 9045 } 9046 9047 /* 9048 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. 9049 */ 9050 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9051 { 9052 DMPolytopeType cct; 9053 PetscInt ptpoints[4]; 9054 const PetscInt *cone, *ccone, *ptcone; 9055 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9056 9057 PetscFunctionBegin; 9058 *unsplit = 0; 9059 switch (ct) { 9060 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9061 ptpoints[npt++] = c; 9062 break; 9063 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9064 PetscCall(DMPlexGetCone(dm, c, &cone)); 9065 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9066 for (cp = 0; cp < coneSize; ++cp) { 9067 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9068 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9069 } 9070 break; 9071 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9072 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9073 PetscCall(DMPlexGetCone(dm, c, &cone)); 9074 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9075 for (cp = 0; cp < coneSize; ++cp) { 9076 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9077 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9078 for (ccp = 0; ccp < cconeSize; ++ccp) { 9079 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9080 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9081 PetscInt p; 9082 for (p = 0; p < npt; ++p) 9083 if (ptpoints[p] == ccone[ccp]) break; 9084 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9085 } 9086 } 9087 } 9088 break; 9089 default: 9090 break; 9091 } 9092 for (pt = 0; pt < npt; ++pt) { 9093 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9094 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9095 } 9096 PetscFunctionReturn(PETSC_SUCCESS); 9097 } 9098 9099 /*@ 9100 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9101 9102 Input Parameters: 9103 + dm - The `DMPLEX` object 9104 - cellHeight - Normally 0 9105 9106 Level: developer 9107 9108 Notes: 9109 This is a useful diagnostic when creating meshes programmatically. 9110 Currently applicable only to homogeneous simplex or tensor meshes. 9111 9112 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9113 9114 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9115 @*/ 9116 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9117 { 9118 DMPlexInterpolatedFlag interp; 9119 DMPolytopeType ct; 9120 PetscInt vStart, vEnd, cStart, cEnd, c; 9121 9122 PetscFunctionBegin; 9123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9124 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9125 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9126 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9127 for (c = cStart; c < cEnd; ++c) { 9128 PetscInt *closure = NULL; 9129 PetscInt coneSize, closureSize, cl, Nv = 0; 9130 9131 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9132 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9133 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9134 if (interp == DMPLEX_INTERPOLATED_FULL) { 9135 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9136 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)); 9137 } 9138 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9139 for (cl = 0; cl < closureSize * 2; cl += 2) { 9140 const PetscInt p = closure[cl]; 9141 if ((p >= vStart) && (p < vEnd)) ++Nv; 9142 } 9143 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9144 /* Special Case: Tensor faces with identified vertices */ 9145 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9146 PetscInt unsplit; 9147 9148 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9149 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9150 } 9151 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)); 9152 } 9153 PetscFunctionReturn(PETSC_SUCCESS); 9154 } 9155 9156 /*@ 9157 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9158 9159 Collective 9160 9161 Input Parameters: 9162 + dm - The `DMPLEX` object 9163 - cellHeight - Normally 0 9164 9165 Level: developer 9166 9167 Notes: 9168 This is a useful diagnostic when creating meshes programmatically. 9169 This routine is only relevant for meshes that are fully interpolated across all ranks. 9170 It will error out if a partially interpolated mesh is given on some rank. 9171 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9172 9173 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9174 9175 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9176 @*/ 9177 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9178 { 9179 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9180 DMPlexInterpolatedFlag interpEnum; 9181 9182 PetscFunctionBegin; 9183 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9184 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9185 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9186 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9187 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9188 PetscFunctionReturn(PETSC_SUCCESS); 9189 } 9190 9191 PetscCall(DMGetDimension(dm, &dim)); 9192 PetscCall(DMPlexGetDepth(dm, &depth)); 9193 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9194 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9195 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9196 for (c = cStart; c < cEnd; ++c) { 9197 const PetscInt *cone, *ornt, *faceSizes, *faces; 9198 const DMPolytopeType *faceTypes; 9199 DMPolytopeType ct; 9200 PetscInt numFaces, coneSize, f; 9201 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9202 9203 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9204 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9205 if (unsplit) continue; 9206 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9207 PetscCall(DMPlexGetCone(dm, c, &cone)); 9208 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9209 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9210 for (cl = 0; cl < closureSize * 2; cl += 2) { 9211 const PetscInt p = closure[cl]; 9212 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9213 } 9214 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9215 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); 9216 for (f = 0; f < numFaces; ++f) { 9217 DMPolytopeType fct; 9218 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9219 9220 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9221 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9222 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9223 const PetscInt p = fclosure[cl]; 9224 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9225 } 9226 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]); 9227 for (v = 0; v < fnumCorners; ++v) { 9228 if (fclosure[v] != faces[fOff + v]) { 9229 PetscInt v1; 9230 9231 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9232 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9233 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9234 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9235 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9236 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]); 9237 } 9238 } 9239 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9240 fOff += faceSizes[f]; 9241 } 9242 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9243 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9244 } 9245 } 9246 PetscFunctionReturn(PETSC_SUCCESS); 9247 } 9248 9249 /*@ 9250 DMPlexCheckGeometry - Check the geometry of mesh cells 9251 9252 Input Parameter: 9253 . dm - The `DMPLEX` object 9254 9255 Level: developer 9256 9257 Notes: 9258 This is a useful diagnostic when creating meshes programmatically. 9259 9260 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9261 9262 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9263 @*/ 9264 PetscErrorCode DMPlexCheckGeometry(DM dm) 9265 { 9266 Vec coordinates; 9267 PetscReal detJ, J[9], refVol = 1.0; 9268 PetscReal vol; 9269 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9270 9271 PetscFunctionBegin; 9272 PetscCall(DMGetDimension(dm, &dim)); 9273 PetscCall(DMGetCoordinateDim(dm, &dE)); 9274 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9275 PetscCall(DMPlexGetDepth(dm, &depth)); 9276 for (d = 0; d < dim; ++d) refVol *= 2.0; 9277 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9278 /* Make sure local coordinates are created, because that step is collective */ 9279 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9280 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9281 for (c = cStart; c < cEnd; ++c) { 9282 DMPolytopeType ct; 9283 PetscInt unsplit; 9284 PetscBool ignoreZeroVol = PETSC_FALSE; 9285 9286 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9287 switch (ct) { 9288 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9289 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9290 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9291 ignoreZeroVol = PETSC_TRUE; 9292 break; 9293 default: 9294 break; 9295 } 9296 switch (ct) { 9297 case DM_POLYTOPE_TRI_PRISM: 9298 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9299 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9300 case DM_POLYTOPE_PYRAMID: 9301 continue; 9302 default: 9303 break; 9304 } 9305 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9306 if (unsplit) continue; 9307 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9308 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); 9309 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9310 /* This should work with periodicity since DG coordinates should be used */ 9311 if (depth > 1) { 9312 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9313 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); 9314 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9315 } 9316 } 9317 PetscFunctionReturn(PETSC_SUCCESS); 9318 } 9319 9320 /*@ 9321 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9322 9323 Collective 9324 9325 Input Parameters: 9326 + dm - The `DMPLEX` object 9327 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9328 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9329 9330 Level: developer 9331 9332 Notes: 9333 This is mainly intended for debugging/testing purposes. 9334 9335 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9336 9337 Extra roots can come from periodic cuts, where additional points appear on the boundary 9338 9339 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9340 @*/ 9341 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9342 { 9343 PetscInt l, nleaves, nroots, overlap; 9344 const PetscInt *locals; 9345 const PetscSFNode *remotes; 9346 PetscBool distributed; 9347 MPI_Comm comm; 9348 PetscMPIInt rank; 9349 9350 PetscFunctionBegin; 9351 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9352 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9353 else pointSF = dm->sf; 9354 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9355 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9356 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9357 { 9358 PetscMPIInt mpiFlag; 9359 9360 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9361 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9362 } 9363 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9364 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9365 if (!distributed) { 9366 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); 9367 PetscFunctionReturn(PETSC_SUCCESS); 9368 } 9369 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); 9370 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9371 9372 /* Check SF graph is compatible with DMPlex chart */ 9373 { 9374 PetscInt pStart, pEnd, maxLeaf; 9375 9376 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9377 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9378 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9379 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9380 } 9381 9382 /* Check Point SF has no local points referenced */ 9383 for (l = 0; l < nleaves; l++) { 9384 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); 9385 } 9386 9387 /* Check there are no cells in interface */ 9388 if (!overlap) { 9389 PetscInt cellHeight, cStart, cEnd; 9390 9391 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9392 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9393 for (l = 0; l < nleaves; ++l) { 9394 const PetscInt point = locals ? locals[l] : l; 9395 9396 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9397 } 9398 } 9399 9400 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9401 { 9402 const PetscInt *rootdegree; 9403 9404 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9405 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9406 for (l = 0; l < nleaves; ++l) { 9407 const PetscInt point = locals ? locals[l] : l; 9408 const PetscInt *cone; 9409 PetscInt coneSize, c, idx; 9410 9411 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9412 PetscCall(DMPlexGetCone(dm, point, &cone)); 9413 for (c = 0; c < coneSize; ++c) { 9414 if (!rootdegree[cone[c]]) { 9415 if (locals) { 9416 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9417 } else { 9418 idx = (cone[c] < nleaves) ? cone[c] : -1; 9419 } 9420 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9421 } 9422 } 9423 } 9424 } 9425 PetscFunctionReturn(PETSC_SUCCESS); 9426 } 9427 9428 /*@ 9429 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9430 9431 Input Parameter: 9432 . dm - The `DMPLEX` object 9433 9434 Level: developer 9435 9436 Notes: 9437 This is a useful diagnostic when creating meshes programmatically. 9438 9439 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9440 9441 Currently does not include `DMPlexCheckCellShape()`. 9442 9443 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9444 @*/ 9445 PetscErrorCode DMPlexCheck(DM dm) 9446 { 9447 PetscInt cellHeight; 9448 9449 PetscFunctionBegin; 9450 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9451 PetscCall(DMPlexCheckSymmetry(dm)); 9452 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9453 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9454 PetscCall(DMPlexCheckGeometry(dm)); 9455 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9456 PetscCall(DMPlexCheckInterfaceCones(dm)); 9457 PetscFunctionReturn(PETSC_SUCCESS); 9458 } 9459 9460 typedef struct cell_stats { 9461 PetscReal min, max, sum, squaresum; 9462 PetscInt count; 9463 } cell_stats_t; 9464 9465 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9466 { 9467 PetscInt i, N = *len; 9468 9469 for (i = 0; i < N; i++) { 9470 cell_stats_t *A = (cell_stats_t *)a; 9471 cell_stats_t *B = (cell_stats_t *)b; 9472 9473 B->min = PetscMin(A->min, B->min); 9474 B->max = PetscMax(A->max, B->max); 9475 B->sum += A->sum; 9476 B->squaresum += A->squaresum; 9477 B->count += A->count; 9478 } 9479 } 9480 9481 /*@ 9482 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9483 9484 Collective 9485 9486 Input Parameters: 9487 + dm - The `DMPLEX` object 9488 . output - If true, statistics will be displayed on `stdout` 9489 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9490 9491 Level: developer 9492 9493 Notes: 9494 This is mainly intended for debugging/testing purposes. 9495 9496 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9497 9498 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9499 @*/ 9500 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9501 { 9502 DM dmCoarse; 9503 cell_stats_t stats, globalStats; 9504 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9505 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9506 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9507 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9508 PetscMPIInt rank, size; 9509 9510 PetscFunctionBegin; 9511 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9512 stats.min = PETSC_MAX_REAL; 9513 stats.max = PETSC_MIN_REAL; 9514 stats.sum = stats.squaresum = 0.; 9515 stats.count = 0; 9516 9517 PetscCallMPI(MPI_Comm_size(comm, &size)); 9518 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9519 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9520 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9521 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9522 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9523 for (c = cStart; c < cEnd; c++) { 9524 PetscInt i; 9525 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9526 9527 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9528 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9529 for (i = 0; i < PetscSqr(cdim); ++i) { 9530 frobJ += J[i] * J[i]; 9531 frobInvJ += invJ[i] * invJ[i]; 9532 } 9533 cond2 = frobJ * frobInvJ; 9534 cond = PetscSqrtReal(cond2); 9535 9536 stats.min = PetscMin(stats.min, cond); 9537 stats.max = PetscMax(stats.max, cond); 9538 stats.sum += cond; 9539 stats.squaresum += cond2; 9540 stats.count++; 9541 if (output && cond > limit) { 9542 PetscSection coordSection; 9543 Vec coordsLocal; 9544 PetscScalar *coords = NULL; 9545 PetscInt Nv, d, clSize, cl, *closure = NULL; 9546 9547 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9548 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9549 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9550 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9551 for (i = 0; i < Nv / cdim; ++i) { 9552 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9553 for (d = 0; d < cdim; ++d) { 9554 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9555 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9556 } 9557 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9558 } 9559 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9560 for (cl = 0; cl < clSize * 2; cl += 2) { 9561 const PetscInt edge = closure[cl]; 9562 9563 if ((edge >= eStart) && (edge < eEnd)) { 9564 PetscReal len; 9565 9566 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9567 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9568 } 9569 } 9570 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9571 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9572 } 9573 } 9574 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9575 9576 if (size > 1) { 9577 PetscMPIInt blockLengths[2] = {4, 1}; 9578 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9579 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9580 MPI_Op statReduce; 9581 9582 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9583 PetscCallMPI(MPI_Type_commit(&statType)); 9584 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9585 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9586 PetscCallMPI(MPI_Op_free(&statReduce)); 9587 PetscCallMPI(MPI_Type_free(&statType)); 9588 } else { 9589 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9590 } 9591 if (rank == 0) { 9592 count = globalStats.count; 9593 min = globalStats.min; 9594 max = globalStats.max; 9595 mean = globalStats.sum / globalStats.count; 9596 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9597 } 9598 9599 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)); 9600 PetscCall(PetscFree2(J, invJ)); 9601 9602 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9603 if (dmCoarse) { 9604 PetscBool isplex; 9605 9606 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9607 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9608 } 9609 PetscFunctionReturn(PETSC_SUCCESS); 9610 } 9611 9612 /*@ 9613 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9614 orthogonal quality below given tolerance. 9615 9616 Collective 9617 9618 Input Parameters: 9619 + dm - The `DMPLEX` object 9620 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9621 - atol - [0, 1] Absolute tolerance for tagging cells. 9622 9623 Output Parameters: 9624 + OrthQual - `Vec` containing orthogonal quality per cell 9625 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9626 9627 Options Database Keys: 9628 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9629 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9630 9631 Level: intermediate 9632 9633 Notes: 9634 Orthogonal quality is given by the following formula\: 9635 9636 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9637 9638 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 9639 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9640 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9641 calculating the cosine of the angle between these vectors. 9642 9643 Orthogonal quality ranges from 1 (best) to 0 (worst). 9644 9645 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9646 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9647 9648 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9649 9650 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9651 @*/ 9652 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9653 { 9654 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9655 PetscInt *idx; 9656 PetscScalar *oqVals; 9657 const PetscScalar *cellGeomArr, *faceGeomArr; 9658 PetscReal *ci, *fi, *Ai; 9659 MPI_Comm comm; 9660 Vec cellgeom, facegeom; 9661 DM dmFace, dmCell; 9662 IS glob; 9663 ISLocalToGlobalMapping ltog; 9664 PetscViewer vwr; 9665 9666 PetscFunctionBegin; 9667 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9668 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9669 PetscAssertPointer(OrthQual, 4); 9670 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9671 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9672 PetscCall(DMGetDimension(dm, &nc)); 9673 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9674 { 9675 DMPlexInterpolatedFlag interpFlag; 9676 9677 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9678 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9679 PetscMPIInt rank; 9680 9681 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9682 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9683 } 9684 } 9685 if (OrthQualLabel) { 9686 PetscAssertPointer(OrthQualLabel, 5); 9687 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9688 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9689 } else { 9690 *OrthQualLabel = NULL; 9691 } 9692 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9693 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9694 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9695 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9696 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9697 PetscCall(VecCreate(comm, OrthQual)); 9698 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9699 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9700 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9701 PetscCall(VecSetUp(*OrthQual)); 9702 PetscCall(ISDestroy(&glob)); 9703 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9704 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9705 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9706 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9707 PetscCall(VecGetDM(cellgeom, &dmCell)); 9708 PetscCall(VecGetDM(facegeom, &dmFace)); 9709 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9710 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9711 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9712 PetscInt cellarr[2], *adj = NULL; 9713 PetscScalar *cArr, *fArr; 9714 PetscReal minvalc = 1.0, minvalf = 1.0; 9715 PetscFVCellGeom *cg; 9716 9717 idx[cellIter] = cell - cStart; 9718 cellarr[0] = cell; 9719 /* Make indexing into cellGeom easier */ 9720 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9721 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9722 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9723 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9724 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9725 PetscInt i; 9726 const PetscInt neigh = adj[cellneigh]; 9727 PetscReal normci = 0, normfi = 0, normai = 0; 9728 PetscFVCellGeom *cgneigh; 9729 PetscFVFaceGeom *fg; 9730 9731 /* Don't count ourselves in the neighbor list */ 9732 if (neigh == cell) continue; 9733 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9734 cellarr[1] = neigh; 9735 { 9736 PetscInt numcovpts; 9737 const PetscInt *covpts; 9738 9739 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9740 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9741 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9742 } 9743 9744 /* Compute c_i, f_i and their norms */ 9745 for (i = 0; i < nc; i++) { 9746 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9747 fi[i] = fg->centroid[i] - cg->centroid[i]; 9748 Ai[i] = fg->normal[i]; 9749 normci += PetscPowReal(ci[i], 2); 9750 normfi += PetscPowReal(fi[i], 2); 9751 normai += PetscPowReal(Ai[i], 2); 9752 } 9753 normci = PetscSqrtReal(normci); 9754 normfi = PetscSqrtReal(normfi); 9755 normai = PetscSqrtReal(normai); 9756 9757 /* Normalize and compute for each face-cell-normal pair */ 9758 for (i = 0; i < nc; i++) { 9759 ci[i] = ci[i] / normci; 9760 fi[i] = fi[i] / normfi; 9761 Ai[i] = Ai[i] / normai; 9762 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9763 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9764 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9765 } 9766 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9767 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9768 } 9769 PetscCall(PetscFree(adj)); 9770 PetscCall(PetscFree2(cArr, fArr)); 9771 /* Defer to cell if they're equal */ 9772 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9773 if (OrthQualLabel) { 9774 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9775 } 9776 } 9777 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9778 PetscCall(VecAssemblyBegin(*OrthQual)); 9779 PetscCall(VecAssemblyEnd(*OrthQual)); 9780 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9781 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9782 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9783 if (OrthQualLabel) { 9784 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9785 } 9786 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9787 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9788 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9789 PetscFunctionReturn(PETSC_SUCCESS); 9790 } 9791 9792 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9793 * interpolator construction */ 9794 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9795 { 9796 PetscSection section, newSection, gsection; 9797 PetscSF sf; 9798 PetscBool hasConstraints, ghasConstraints; 9799 9800 PetscFunctionBegin; 9801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9802 PetscAssertPointer(odm, 2); 9803 PetscCall(DMGetLocalSection(dm, §ion)); 9804 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9805 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9806 if (!ghasConstraints) { 9807 PetscCall(PetscObjectReference((PetscObject)dm)); 9808 *odm = dm; 9809 PetscFunctionReturn(PETSC_SUCCESS); 9810 } 9811 PetscCall(DMClone(dm, odm)); 9812 PetscCall(DMCopyFields(dm, *odm)); 9813 PetscCall(DMGetLocalSection(*odm, &newSection)); 9814 PetscCall(DMGetPointSF(*odm, &sf)); 9815 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9816 PetscCall(DMSetGlobalSection(*odm, gsection)); 9817 PetscCall(PetscSectionDestroy(&gsection)); 9818 PetscFunctionReturn(PETSC_SUCCESS); 9819 } 9820 9821 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9822 { 9823 DM dmco, dmfo; 9824 Mat interpo; 9825 Vec rscale; 9826 Vec cglobalo, clocal; 9827 Vec fglobal, fglobalo, flocal; 9828 PetscBool regular; 9829 9830 PetscFunctionBegin; 9831 PetscCall(DMGetFullDM(dmc, &dmco)); 9832 PetscCall(DMGetFullDM(dmf, &dmfo)); 9833 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9834 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9835 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9836 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9837 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9838 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9839 PetscCall(VecSet(cglobalo, 0.)); 9840 PetscCall(VecSet(clocal, 0.)); 9841 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9842 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9843 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9844 PetscCall(VecSet(fglobal, 0.)); 9845 PetscCall(VecSet(fglobalo, 0.)); 9846 PetscCall(VecSet(flocal, 0.)); 9847 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9848 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9849 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9850 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9851 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9852 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9853 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9854 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9855 *shift = fglobal; 9856 PetscCall(VecDestroy(&flocal)); 9857 PetscCall(VecDestroy(&fglobalo)); 9858 PetscCall(VecDestroy(&clocal)); 9859 PetscCall(VecDestroy(&cglobalo)); 9860 PetscCall(VecDestroy(&rscale)); 9861 PetscCall(MatDestroy(&interpo)); 9862 PetscCall(DMDestroy(&dmfo)); 9863 PetscCall(DMDestroy(&dmco)); 9864 PetscFunctionReturn(PETSC_SUCCESS); 9865 } 9866 9867 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9868 { 9869 PetscObject shifto; 9870 Vec shift; 9871 9872 PetscFunctionBegin; 9873 if (!interp) { 9874 Vec rscale; 9875 9876 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9877 PetscCall(VecDestroy(&rscale)); 9878 } else { 9879 PetscCall(PetscObjectReference((PetscObject)interp)); 9880 } 9881 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9882 if (!shifto) { 9883 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9884 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9885 shifto = (PetscObject)shift; 9886 PetscCall(VecDestroy(&shift)); 9887 } 9888 shift = (Vec)shifto; 9889 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9890 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9891 PetscCall(MatDestroy(&interp)); 9892 PetscFunctionReturn(PETSC_SUCCESS); 9893 } 9894 9895 /* Pointwise interpolation 9896 Just code FEM for now 9897 u^f = I u^c 9898 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9899 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9900 I_{ij} = psi^f_i phi^c_j 9901 */ 9902 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9903 { 9904 PetscSection gsc, gsf; 9905 PetscInt m, n; 9906 void *ctx; 9907 DM cdm; 9908 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9909 9910 PetscFunctionBegin; 9911 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9912 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9913 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9914 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9915 9916 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9917 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9918 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9919 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9920 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9921 9922 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9923 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9924 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9925 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9926 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9927 if (scaling) { 9928 /* Use naive scaling */ 9929 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9930 } 9931 PetscFunctionReturn(PETSC_SUCCESS); 9932 } 9933 9934 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9935 { 9936 VecScatter ctx; 9937 9938 PetscFunctionBegin; 9939 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9940 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9941 PetscCall(VecScatterDestroy(&ctx)); 9942 PetscFunctionReturn(PETSC_SUCCESS); 9943 } 9944 9945 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[]) 9946 { 9947 const PetscInt Nc = uOff[1] - uOff[0]; 9948 PetscInt c; 9949 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9950 } 9951 9952 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9953 { 9954 DM dmc; 9955 PetscDS ds; 9956 Vec ones, locmass; 9957 IS cellIS; 9958 PetscFormKey key; 9959 PetscInt depth; 9960 9961 PetscFunctionBegin; 9962 PetscCall(DMClone(dm, &dmc)); 9963 PetscCall(DMCopyDisc(dm, dmc)); 9964 PetscCall(DMGetDS(dmc, &ds)); 9965 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9966 PetscCall(DMCreateGlobalVector(dmc, mass)); 9967 PetscCall(DMGetLocalVector(dmc, &ones)); 9968 PetscCall(DMGetLocalVector(dmc, &locmass)); 9969 PetscCall(DMPlexGetDepth(dmc, &depth)); 9970 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9971 PetscCall(VecSet(locmass, 0.0)); 9972 PetscCall(VecSet(ones, 1.0)); 9973 key.label = NULL; 9974 key.value = 0; 9975 key.field = 0; 9976 key.part = 0; 9977 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9978 PetscCall(ISDestroy(&cellIS)); 9979 PetscCall(VecSet(*mass, 0.0)); 9980 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9981 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9982 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9983 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9984 PetscCall(DMDestroy(&dmc)); 9985 PetscFunctionReturn(PETSC_SUCCESS); 9986 } 9987 9988 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9989 { 9990 PetscSection gsc, gsf; 9991 PetscInt m, n; 9992 void *ctx; 9993 DM cdm; 9994 PetscBool regular; 9995 9996 PetscFunctionBegin; 9997 if (dmFine == dmCoarse) { 9998 DM dmc; 9999 PetscDS ds; 10000 PetscWeakForm wf; 10001 Vec u; 10002 IS cellIS; 10003 PetscFormKey key; 10004 PetscInt depth; 10005 10006 PetscCall(DMClone(dmFine, &dmc)); 10007 PetscCall(DMCopyDisc(dmFine, dmc)); 10008 PetscCall(DMGetDS(dmc, &ds)); 10009 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10010 PetscCall(PetscWeakFormClear(wf)); 10011 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10012 PetscCall(DMCreateMatrix(dmc, mass)); 10013 PetscCall(DMGetLocalVector(dmc, &u)); 10014 PetscCall(DMPlexGetDepth(dmc, &depth)); 10015 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10016 PetscCall(MatZeroEntries(*mass)); 10017 key.label = NULL; 10018 key.value = 0; 10019 key.field = 0; 10020 key.part = 0; 10021 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10022 PetscCall(ISDestroy(&cellIS)); 10023 PetscCall(DMRestoreLocalVector(dmc, &u)); 10024 PetscCall(DMDestroy(&dmc)); 10025 } else { 10026 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10027 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10028 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10029 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10030 10031 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10032 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10033 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10034 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10035 10036 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10037 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10038 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10039 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10040 } 10041 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10042 PetscFunctionReturn(PETSC_SUCCESS); 10043 } 10044 10045 /*@ 10046 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10047 10048 Input Parameter: 10049 . dm - The `DMPLEX` object 10050 10051 Output Parameter: 10052 . regular - The flag 10053 10054 Level: intermediate 10055 10056 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10057 @*/ 10058 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10059 { 10060 PetscFunctionBegin; 10061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10062 PetscAssertPointer(regular, 2); 10063 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10064 PetscFunctionReturn(PETSC_SUCCESS); 10065 } 10066 10067 /*@ 10068 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10069 10070 Input Parameters: 10071 + dm - The `DMPLEX` object 10072 - regular - The flag 10073 10074 Level: intermediate 10075 10076 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10077 @*/ 10078 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10079 { 10080 PetscFunctionBegin; 10081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10082 ((DM_Plex *)dm->data)->regularRefinement = regular; 10083 PetscFunctionReturn(PETSC_SUCCESS); 10084 } 10085 10086 /*@ 10087 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10088 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10089 10090 Not Collective 10091 10092 Input Parameter: 10093 . dm - The `DMPLEX` object 10094 10095 Output Parameters: 10096 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10097 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10098 10099 Level: intermediate 10100 10101 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10102 @*/ 10103 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10104 { 10105 DM_Plex *plex = (DM_Plex *)dm->data; 10106 10107 PetscFunctionBegin; 10108 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10109 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10110 if (anchorSection) *anchorSection = plex->anchorSection; 10111 if (anchorIS) *anchorIS = plex->anchorIS; 10112 PetscFunctionReturn(PETSC_SUCCESS); 10113 } 10114 10115 /*@ 10116 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10117 10118 Collective 10119 10120 Input Parameters: 10121 + dm - The `DMPLEX` object 10122 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10123 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10124 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10125 10126 Level: intermediate 10127 10128 Notes: 10129 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10130 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10131 combination of other points' degrees of freedom. 10132 10133 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10134 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10135 10136 The reference counts of `anchorSection` and `anchorIS` are incremented. 10137 10138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10139 @*/ 10140 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10141 { 10142 DM_Plex *plex = (DM_Plex *)dm->data; 10143 PetscMPIInt result; 10144 10145 PetscFunctionBegin; 10146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10147 if (anchorSection) { 10148 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10149 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10150 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10151 } 10152 if (anchorIS) { 10153 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10154 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10155 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10156 } 10157 10158 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10159 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10160 plex->anchorSection = anchorSection; 10161 10162 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10163 PetscCall(ISDestroy(&plex->anchorIS)); 10164 plex->anchorIS = anchorIS; 10165 10166 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10167 PetscInt size, a, pStart, pEnd; 10168 const PetscInt *anchors; 10169 10170 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10171 PetscCall(ISGetLocalSize(anchorIS, &size)); 10172 PetscCall(ISGetIndices(anchorIS, &anchors)); 10173 for (a = 0; a < size; a++) { 10174 PetscInt p; 10175 10176 p = anchors[a]; 10177 if (p >= pStart && p < pEnd) { 10178 PetscInt dof; 10179 10180 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10181 if (dof) { 10182 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10183 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10184 } 10185 } 10186 } 10187 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10188 } 10189 /* reset the generic constraints */ 10190 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10191 PetscFunctionReturn(PETSC_SUCCESS); 10192 } 10193 10194 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10195 { 10196 PetscSection anchorSection; 10197 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10198 10199 PetscFunctionBegin; 10200 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10201 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10202 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10203 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10204 if (numFields) { 10205 PetscInt f; 10206 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10207 10208 for (f = 0; f < numFields; f++) { 10209 PetscInt numComp; 10210 10211 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10212 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10213 } 10214 } 10215 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10216 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10217 pStart = PetscMax(pStart, sStart); 10218 pEnd = PetscMin(pEnd, sEnd); 10219 pEnd = PetscMax(pStart, pEnd); 10220 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10221 for (p = pStart; p < pEnd; p++) { 10222 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10223 if (dof) { 10224 PetscCall(PetscSectionGetDof(section, p, &dof)); 10225 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10226 for (f = 0; f < numFields; f++) { 10227 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10228 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10229 } 10230 } 10231 } 10232 PetscCall(PetscSectionSetUp(*cSec)); 10233 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10234 PetscFunctionReturn(PETSC_SUCCESS); 10235 } 10236 10237 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10238 { 10239 PetscSection aSec; 10240 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10241 const PetscInt *anchors; 10242 PetscInt numFields, f; 10243 IS aIS; 10244 MatType mtype; 10245 PetscBool iscuda, iskokkos; 10246 10247 PetscFunctionBegin; 10248 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10249 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10250 PetscCall(PetscSectionGetStorageSize(section, &n)); 10251 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10252 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10253 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10254 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10255 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10256 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10257 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10258 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10259 else mtype = MATSEQAIJ; 10260 PetscCall(MatSetType(*cMat, mtype)); 10261 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10262 PetscCall(ISGetIndices(aIS, &anchors)); 10263 /* cSec will be a subset of aSec and section */ 10264 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10265 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10266 PetscCall(PetscMalloc1(m + 1, &i)); 10267 i[0] = 0; 10268 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10269 for (p = pStart; p < pEnd; p++) { 10270 PetscInt rDof, rOff, r; 10271 10272 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10273 if (!rDof) continue; 10274 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10275 if (numFields) { 10276 for (f = 0; f < numFields; f++) { 10277 annz = 0; 10278 for (r = 0; r < rDof; r++) { 10279 a = anchors[rOff + r]; 10280 if (a < sStart || a >= sEnd) continue; 10281 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10282 annz += aDof; 10283 } 10284 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10285 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10286 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10287 } 10288 } else { 10289 annz = 0; 10290 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10291 for (q = 0; q < dof; q++) { 10292 a = anchors[rOff + q]; 10293 if (a < sStart || a >= sEnd) continue; 10294 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10295 annz += aDof; 10296 } 10297 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10298 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10299 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10300 } 10301 } 10302 nnz = i[m]; 10303 PetscCall(PetscMalloc1(nnz, &j)); 10304 offset = 0; 10305 for (p = pStart; p < pEnd; p++) { 10306 if (numFields) { 10307 for (f = 0; f < numFields; f++) { 10308 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10309 for (q = 0; q < dof; q++) { 10310 PetscInt rDof, rOff, r; 10311 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10312 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10313 for (r = 0; r < rDof; r++) { 10314 PetscInt s; 10315 10316 a = anchors[rOff + r]; 10317 if (a < sStart || a >= sEnd) continue; 10318 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10319 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10320 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10321 } 10322 } 10323 } 10324 } else { 10325 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10326 for (q = 0; q < dof; q++) { 10327 PetscInt rDof, rOff, r; 10328 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10329 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10330 for (r = 0; r < rDof; r++) { 10331 PetscInt s; 10332 10333 a = anchors[rOff + r]; 10334 if (a < sStart || a >= sEnd) continue; 10335 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10336 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10337 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10338 } 10339 } 10340 } 10341 } 10342 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10343 PetscCall(PetscFree(i)); 10344 PetscCall(PetscFree(j)); 10345 PetscCall(ISRestoreIndices(aIS, &anchors)); 10346 PetscFunctionReturn(PETSC_SUCCESS); 10347 } 10348 10349 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10350 { 10351 DM_Plex *plex = (DM_Plex *)dm->data; 10352 PetscSection anchorSection, section, cSec; 10353 Mat cMat; 10354 10355 PetscFunctionBegin; 10356 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10357 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10358 if (anchorSection) { 10359 PetscInt Nf; 10360 10361 PetscCall(DMGetLocalSection(dm, §ion)); 10362 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10363 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10364 PetscCall(DMGetNumFields(dm, &Nf)); 10365 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10366 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10367 PetscCall(PetscSectionDestroy(&cSec)); 10368 PetscCall(MatDestroy(&cMat)); 10369 } 10370 PetscFunctionReturn(PETSC_SUCCESS); 10371 } 10372 10373 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10374 { 10375 IS subis; 10376 PetscSection section, subsection; 10377 10378 PetscFunctionBegin; 10379 PetscCall(DMGetLocalSection(dm, §ion)); 10380 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10381 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10382 /* Create subdomain */ 10383 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10384 /* Create submodel */ 10385 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10386 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10387 PetscCall(DMSetLocalSection(*subdm, subsection)); 10388 PetscCall(PetscSectionDestroy(&subsection)); 10389 PetscCall(DMCopyDisc(dm, *subdm)); 10390 /* Create map from submodel to global model */ 10391 if (is) { 10392 PetscSection sectionGlobal, subsectionGlobal; 10393 IS spIS; 10394 const PetscInt *spmap; 10395 PetscInt *subIndices; 10396 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10397 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10398 10399 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10400 PetscCall(ISGetIndices(spIS, &spmap)); 10401 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10402 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10403 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10404 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10405 for (p = pStart; p < pEnd; ++p) { 10406 PetscInt gdof, pSubSize = 0; 10407 10408 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10409 if (gdof > 0) { 10410 for (f = 0; f < Nf; ++f) { 10411 PetscInt fdof, fcdof; 10412 10413 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10414 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10415 pSubSize += fdof - fcdof; 10416 } 10417 subSize += pSubSize; 10418 if (pSubSize) { 10419 if (bs < 0) { 10420 bs = pSubSize; 10421 } else if (bs != pSubSize) { 10422 /* Layout does not admit a pointwise block size */ 10423 bs = 1; 10424 } 10425 } 10426 } 10427 } 10428 /* Must have same blocksize on all procs (some might have no points) */ 10429 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10430 bsLocal[1] = bs; 10431 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10432 if (bsMinMax[0] != bsMinMax[1]) { 10433 bs = 1; 10434 } else { 10435 bs = bsMinMax[0]; 10436 } 10437 PetscCall(PetscMalloc1(subSize, &subIndices)); 10438 for (p = pStart; p < pEnd; ++p) { 10439 PetscInt gdof, goff; 10440 10441 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10442 if (gdof > 0) { 10443 const PetscInt point = spmap[p]; 10444 10445 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10446 for (f = 0; f < Nf; ++f) { 10447 PetscInt fdof, fcdof, fc, f2, poff = 0; 10448 10449 /* Can get rid of this loop by storing field information in the global section */ 10450 for (f2 = 0; f2 < f; ++f2) { 10451 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10452 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10453 poff += fdof - fcdof; 10454 } 10455 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10456 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10457 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10458 } 10459 } 10460 } 10461 PetscCall(ISRestoreIndices(spIS, &spmap)); 10462 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10463 if (bs > 1) { 10464 /* We need to check that the block size does not come from non-contiguous fields */ 10465 PetscInt i, j, set = 1; 10466 for (i = 0; i < subSize; i += bs) { 10467 for (j = 0; j < bs; ++j) { 10468 if (subIndices[i + j] != subIndices[i] + j) { 10469 set = 0; 10470 break; 10471 } 10472 } 10473 } 10474 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10475 } 10476 /* Attach nullspace */ 10477 for (f = 0; f < Nf; ++f) { 10478 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10479 if ((*subdm)->nullspaceConstructors[f]) break; 10480 } 10481 if (f < Nf) { 10482 MatNullSpace nullSpace; 10483 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10484 10485 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10486 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10487 } 10488 } 10489 PetscFunctionReturn(PETSC_SUCCESS); 10490 } 10491 10492 /*@ 10493 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10494 10495 Input Parameters: 10496 + dm - The `DM` 10497 - dummy - unused argument 10498 10499 Options Database Key: 10500 . -dm_plex_monitor_throughput - Activate the monitor 10501 10502 Level: developer 10503 10504 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10505 @*/ 10506 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10507 { 10508 PetscLogHandler default_handler; 10509 10510 PetscFunctionBegin; 10511 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10512 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10513 if (default_handler) { 10514 PetscLogEvent event; 10515 PetscEventPerfInfo eventInfo; 10516 PetscReal cellRate, flopRate; 10517 PetscInt cStart, cEnd, Nf, N; 10518 const char *name; 10519 10520 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10521 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10522 PetscCall(DMGetNumFields(dm, &Nf)); 10523 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10524 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10525 N = (cEnd - cStart) * Nf * eventInfo.count; 10526 flopRate = eventInfo.flops / eventInfo.time; 10527 cellRate = N / eventInfo.time; 10528 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))); 10529 } else { 10530 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."); 10531 } 10532 PetscFunctionReturn(PETSC_SUCCESS); 10533 } 10534