1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 89 90 PetscFunctionBegin; 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 93 PetscCall(ISGetLocalSize(valueIS, &Nct)); 94 PetscCall(ISGetIndices(valueIS, &ctypes)); 95 if (!Nct) cS = cE = 0; 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 } 114 PetscCall(ISDestroy(&valueIS)); 115 // Reset label for fast lookup 116 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 117 if (cStart) *cStart = cS; 118 if (cEnd) *cEnd = cE; 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 123 { 124 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 125 PetscInt *sStart, *sEnd; 126 PetscViewerVTKFieldType *ft; 127 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 128 DMLabel depthLabel, ctLabel; 129 130 PetscFunctionBegin; 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 } 162 163 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 164 *types = 0; 165 166 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 167 if (globalvcdof[c]) ++(*types); 168 } 169 170 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 171 t = 0; 172 if (globalvcdof[DM_NUM_POLYTOPES]) { 173 sStart[t] = vStart; 174 sEnd[t] = vEnd; 175 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 176 ++t; 177 } 178 179 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 180 if (globalvcdof[c]) { 181 const DMPolytopeType ict = (DMPolytopeType)c; 182 183 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 184 sStart[t] = cStart; 185 sEnd[t] = cEnd; 186 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 187 ++t; 188 } 189 } 190 191 if (!*types) { 192 if (field >= 0) { 193 const char *fieldname; 194 195 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 196 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 197 } else { 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 199 } 200 } 201 202 *ssStart = sStart; 203 *ssEnd = sEnd; 204 *sft = ft; 205 PetscFunctionReturn(PETSC_SUCCESS); 206 } 207 208 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 209 { 210 PetscFunctionBegin; 211 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 216 { 217 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 218 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 219 220 PetscFunctionBegin; 221 *ft = PETSC_VTK_INVALID; 222 PetscCall(DMGetCoordinateDim(dm, &cdim)); 223 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 224 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 225 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 226 if (field >= 0) { 227 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 228 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 229 } else { 230 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 231 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 232 } 233 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 234 if (globalvcdof[0]) { 235 *sStart = vStart; 236 *sEnd = vEnd; 237 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 238 else *ft = PETSC_VTK_POINT_FIELD; 239 } else if (globalvcdof[1]) { 240 *sStart = cStart; 241 *sEnd = cEnd; 242 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 243 else *ft = PETSC_VTK_CELL_FIELD; 244 } else { 245 if (field >= 0) { 246 const char *fieldname; 247 248 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 249 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 250 } else { 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 252 } 253 } 254 PetscFunctionReturn(PETSC_SUCCESS); 255 } 256 257 /*@ 258 DMPlexVecView1D - Plot many 1D solutions on the same line graph 259 260 Collective 261 262 Input Parameters: 263 + dm - The `DMPLEX` object 264 . n - The number of vectors 265 . u - The array of local vectors 266 - viewer - The `PetscViewer` 267 268 Level: advanced 269 270 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 271 @*/ 272 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 273 { 274 PetscDS ds; 275 PetscDraw draw = NULL; 276 PetscDrawLG lg; 277 Vec coordinates; 278 const PetscScalar *coords, **sol; 279 PetscReal *vals; 280 PetscInt *Nc; 281 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 282 char **names; 283 284 PetscFunctionBegin; 285 PetscCall(DMGetDS(dm, &ds)); 286 PetscCall(PetscDSGetNumFields(ds, &Nf)); 287 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 288 PetscCall(PetscDSGetComponents(ds, &Nc)); 289 290 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 291 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 292 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 293 294 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 295 for (i = 0, l = 0; i < n; ++i) { 296 const char *vname; 297 298 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 299 for (f = 0; f < Nf; ++f) { 300 PetscObject disc; 301 const char *fname; 302 char tmpname[PETSC_MAX_PATH_LEN]; 303 304 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 305 /* TODO Create names for components */ 306 for (c = 0; c < Nc[f]; ++c, ++l) { 307 PetscCall(PetscObjectGetName(disc, &fname)); 308 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 309 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 311 PetscCall(PetscStrallocpy(tmpname, &names[l])); 312 } 313 } 314 } 315 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 316 /* Just add P_1 support for now */ 317 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 318 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 319 PetscCall(VecGetArrayRead(coordinates, &coords)); 320 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 321 for (v = vStart; v < vEnd; ++v) { 322 PetscScalar *x, *svals; 323 324 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 325 for (i = 0; i < n; ++i) { 326 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 327 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 328 } 329 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 330 } 331 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 332 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 333 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 334 PetscCall(PetscFree3(sol, names, vals)); 335 336 PetscCall(PetscDrawLGDraw(lg)); 337 PetscCall(PetscDrawLGDestroy(&lg)); 338 PetscFunctionReturn(PETSC_SUCCESS); 339 } 340 341 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 342 { 343 DM dm; 344 345 PetscFunctionBegin; 346 PetscCall(VecGetDM(u, &dm)); 347 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 348 PetscFunctionReturn(PETSC_SUCCESS); 349 } 350 351 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 352 { 353 DM dm; 354 PetscSection s; 355 PetscDraw draw, popup; 356 DM cdm; 357 PetscSection coordSection; 358 Vec coordinates; 359 const PetscScalar *array; 360 PetscReal lbound[3], ubound[3]; 361 PetscReal vbound[2], time; 362 PetscBool flg; 363 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 364 const char *name; 365 char title[PETSC_MAX_PATH_LEN]; 366 367 PetscFunctionBegin; 368 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 369 PetscCall(VecGetDM(v, &dm)); 370 PetscCall(DMGetCoordinateDim(dm, &dim)); 371 PetscCall(DMGetLocalSection(dm, &s)); 372 PetscCall(PetscSectionGetNumFields(s, &Nf)); 373 PetscCall(DMGetCoarsenLevel(dm, &level)); 374 PetscCall(DMGetCoordinateDM(dm, &cdm)); 375 PetscCall(DMGetLocalSection(cdm, &coordSection)); 376 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 377 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 378 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 379 380 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 381 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 382 383 PetscCall(VecGetLocalSize(coordinates, &N)); 384 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 385 PetscCall(PetscDrawClear(draw)); 386 387 /* Could implement something like DMDASelectFields() */ 388 for (f = 0; f < Nf; ++f) { 389 DM fdm = dm; 390 Vec fv = v; 391 IS fis; 392 char prefix[PETSC_MAX_PATH_LEN]; 393 const char *fname; 394 395 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 396 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 397 398 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 399 else prefix[0] = '\0'; 400 if (Nf > 1) { 401 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 402 PetscCall(VecGetSubVector(v, fis, &fv)); 403 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 404 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 405 } 406 for (comp = 0; comp < Nc; ++comp, ++w) { 407 PetscInt nmax = 2; 408 409 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 410 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 411 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 412 PetscCall(PetscDrawSetTitle(draw, title)); 413 414 /* TODO Get max and min only for this component */ 415 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 416 if (!flg) { 417 PetscCall(VecMin(fv, NULL, &vbound[0])); 418 PetscCall(VecMax(fv, NULL, &vbound[1])); 419 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 420 } 421 422 PetscCall(PetscDrawGetPopup(draw, &popup)); 423 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 424 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 425 PetscCall(VecGetArrayRead(fv, &array)); 426 for (c = cStart; c < cEnd; ++c) { 427 PetscScalar *coords = NULL, *a = NULL; 428 const PetscScalar *coords_arr; 429 PetscBool isDG; 430 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 431 432 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 433 if (a) { 434 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 435 color[1] = color[2] = color[3] = color[0]; 436 } else { 437 PetscScalar *vals = NULL; 438 PetscInt numVals, va; 439 440 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 441 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 442 switch (numVals / Nc) { 443 case 3: /* P1 Triangle */ 444 case 4: /* P1 Quadrangle */ 445 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 446 break; 447 case 6: /* P2 Triangle */ 448 case 8: /* P2 Quadrangle */ 449 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 450 break; 451 default: 452 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 453 } 454 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 455 } 456 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 457 switch (numCoords) { 458 case 6: 459 case 12: /* Localized triangle */ 460 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 461 break; 462 case 8: 463 case 16: /* Localized quadrilateral */ 464 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 465 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 466 break; 467 default: 468 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 469 } 470 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 471 } 472 PetscCall(VecRestoreArrayRead(fv, &array)); 473 PetscCall(PetscDrawFlush(draw)); 474 PetscCall(PetscDrawPause(draw)); 475 PetscCall(PetscDrawSave(draw)); 476 } 477 if (Nf > 1) { 478 PetscCall(VecRestoreSubVector(v, fis, &fv)); 479 PetscCall(ISDestroy(&fis)); 480 PetscCall(DMDestroy(&fdm)); 481 } 482 } 483 PetscFunctionReturn(PETSC_SUCCESS); 484 } 485 486 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 487 { 488 DM dm; 489 PetscDraw draw; 490 PetscInt dim; 491 PetscBool isnull; 492 493 PetscFunctionBegin; 494 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 495 PetscCall(PetscDrawIsNull(draw, &isnull)); 496 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 497 498 PetscCall(VecGetDM(v, &dm)); 499 PetscCall(DMGetCoordinateDim(dm, &dim)); 500 switch (dim) { 501 case 1: 502 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 503 break; 504 case 2: 505 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 506 break; 507 default: 508 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 509 } 510 PetscFunctionReturn(PETSC_SUCCESS); 511 } 512 513 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 514 { 515 DM dm; 516 Vec locv; 517 const char *name; 518 PetscSection section; 519 PetscInt pStart, pEnd; 520 PetscInt numFields; 521 PetscViewerVTKFieldType ft; 522 523 PetscFunctionBegin; 524 PetscCall(VecGetDM(v, &dm)); 525 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 526 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 527 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 528 PetscCall(VecCopy(v, locv)); 529 PetscCall(DMGetLocalSection(dm, §ion)); 530 PetscCall(PetscSectionGetNumFields(section, &numFields)); 531 if (!numFields) { 532 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 533 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 534 } else { 535 PetscInt f; 536 537 for (f = 0; f < numFields; f++) { 538 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 539 if (ft == PETSC_VTK_INVALID) continue; 540 PetscCall(PetscObjectReference((PetscObject)locv)); 541 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 542 } 543 PetscCall(VecDestroy(&locv)); 544 } 545 PetscFunctionReturn(PETSC_SUCCESS); 546 } 547 548 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 549 { 550 DM dm; 551 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 552 553 PetscFunctionBegin; 554 PetscCall(VecGetDM(v, &dm)); 555 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 561 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 562 PetscInt i, numFields; 563 PetscObject fe; 564 PetscBool fem = PETSC_FALSE; 565 Vec locv = v; 566 const char *name; 567 PetscInt step; 568 PetscReal time; 569 570 PetscCall(DMGetNumFields(dm, &numFields)); 571 for (i = 0; i < numFields; i++) { 572 PetscCall(DMGetField(dm, i, NULL, &fe)); 573 if (fe->classid == PETSCFE_CLASSID) { 574 fem = PETSC_TRUE; 575 break; 576 } 577 } 578 if (fem) { 579 PetscObject isZero; 580 581 PetscCall(DMGetLocalVector(dm, &locv)); 582 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 583 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 584 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 585 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 586 PetscCall(VecCopy(v, locv)); 587 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 588 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 589 } 590 if (isvtk) { 591 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 592 } else if (ishdf5) { 593 #if defined(PETSC_HAVE_HDF5) 594 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 595 #else 596 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 597 #endif 598 } else if (isdraw) { 599 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 600 } else if (isglvis) { 601 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 602 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 603 PetscCall(VecView_GLVis(locv, viewer)); 604 } else if (iscgns) { 605 #if defined(PETSC_HAVE_CGNS) 606 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 607 #else 608 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 609 #endif 610 } 611 if (fem) { 612 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 613 PetscCall(DMRestoreLocalVector(dm, &locv)); 614 } 615 } else { 616 PetscBool isseq; 617 618 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 619 if (isseq) PetscCall(VecView_Seq(v, viewer)); 620 else PetscCall(VecView_MPI(v, viewer)); 621 } 622 PetscFunctionReturn(PETSC_SUCCESS); 623 } 624 625 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 626 { 627 DM dm; 628 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 629 630 PetscFunctionBegin; 631 PetscCall(VecGetDM(v, &dm)); 632 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 633 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 639 if (isvtk || isdraw || isglvis || iscgns) { 640 Vec locv; 641 PetscObject isZero; 642 const char *name; 643 644 PetscCall(DMGetLocalVector(dm, &locv)); 645 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 646 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 647 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 648 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 649 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 650 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 651 PetscCall(VecView_Plex_Local(locv, viewer)); 652 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 653 PetscCall(DMRestoreLocalVector(dm, &locv)); 654 } else if (ishdf5) { 655 #if defined(PETSC_HAVE_HDF5) 656 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 657 #else 658 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 659 #endif 660 } else if (isexodusii) { 661 #if defined(PETSC_HAVE_EXODUSII) 662 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 663 #else 664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 665 #endif 666 } else { 667 PetscBool isseq; 668 669 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 670 if (isseq) PetscCall(VecView_Seq(v, viewer)); 671 else PetscCall(VecView_MPI(v, viewer)); 672 } 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 677 { 678 DM dm; 679 MPI_Comm comm; 680 PetscViewerFormat format; 681 Vec v; 682 PetscBool isvtk, ishdf5; 683 684 PetscFunctionBegin; 685 PetscCall(VecGetDM(originalv, &dm)); 686 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 687 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 688 PetscCall(PetscViewerGetFormat(viewer, &format)); 689 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 691 if (format == PETSC_VIEWER_NATIVE) { 692 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 693 /* this need a better fix */ 694 if (dm->useNatural) { 695 if (dm->sfNatural) { 696 const char *vecname; 697 PetscInt n, nroots; 698 699 PetscCall(VecGetLocalSize(originalv, &n)); 700 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 701 if (n == nroots) { 702 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 703 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 704 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 705 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 706 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 707 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 709 } else v = originalv; 710 } else v = originalv; 711 712 if (ishdf5) { 713 #if defined(PETSC_HAVE_HDF5) 714 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 715 #else 716 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 717 #endif 718 } else if (isvtk) { 719 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 720 } else { 721 PetscBool isseq; 722 723 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 724 if (isseq) PetscCall(VecView_Seq(v, viewer)); 725 else PetscCall(VecView_MPI(v, viewer)); 726 } 727 if (v != originalv) PetscCall(VecDestroy(&v)); 728 PetscFunctionReturn(PETSC_SUCCESS); 729 } 730 731 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 732 { 733 DM dm; 734 PetscBool ishdf5; 735 736 PetscFunctionBegin; 737 PetscCall(VecGetDM(v, &dm)); 738 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 739 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 740 if (ishdf5) { 741 DM dmBC; 742 Vec gv; 743 const char *name; 744 745 PetscCall(DMGetOutputDM(dm, &dmBC)); 746 PetscCall(DMGetGlobalVector(dmBC, &gv)); 747 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 748 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 749 PetscCall(VecLoad_Default(gv, viewer)); 750 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 751 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 753 } else PetscCall(VecLoad_Default(v, viewer)); 754 PetscFunctionReturn(PETSC_SUCCESS); 755 } 756 757 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 758 { 759 DM dm; 760 PetscBool ishdf5, isexodusii; 761 762 PetscFunctionBegin; 763 PetscCall(VecGetDM(v, &dm)); 764 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 765 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 767 if (ishdf5) { 768 #if defined(PETSC_HAVE_HDF5) 769 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 770 #else 771 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 772 #endif 773 } else if (isexodusii) { 774 #if defined(PETSC_HAVE_EXODUSII) 775 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 776 #else 777 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 778 #endif 779 } else PetscCall(VecLoad_Default(v, viewer)); 780 PetscFunctionReturn(PETSC_SUCCESS); 781 } 782 783 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 784 { 785 DM dm; 786 PetscViewerFormat format; 787 PetscBool ishdf5; 788 789 PetscFunctionBegin; 790 PetscCall(VecGetDM(originalv, &dm)); 791 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 792 PetscCall(PetscViewerGetFormat(viewer, &format)); 793 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 794 if (format == PETSC_VIEWER_NATIVE) { 795 if (dm->useNatural) { 796 if (dm->sfNatural) { 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 Vec v; 800 const char *vecname; 801 802 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 803 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 804 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 805 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 806 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 807 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 808 PetscCall(VecDestroy(&v)); 809 #else 810 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 811 #endif 812 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 813 } 814 } else PetscCall(VecLoad_Default(originalv, viewer)); 815 } 816 PetscFunctionReturn(PETSC_SUCCESS); 817 } 818 819 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 820 { 821 PetscSection coordSection; 822 Vec coordinates; 823 DMLabel depthLabel, celltypeLabel; 824 const char *name[4]; 825 const PetscScalar *a; 826 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 827 828 PetscFunctionBegin; 829 PetscCall(DMGetDimension(dm, &dim)); 830 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 831 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 832 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 833 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 834 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 835 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 836 PetscCall(VecGetArrayRead(coordinates, &a)); 837 name[0] = "vertex"; 838 name[1] = "edge"; 839 name[dim - 1] = "face"; 840 name[dim] = "cell"; 841 for (c = cStart; c < cEnd; ++c) { 842 PetscInt *closure = NULL; 843 PetscInt closureSize, cl, ct; 844 845 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 846 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 847 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 848 PetscCall(PetscViewerASCIIPushTab(viewer)); 849 for (cl = 0; cl < closureSize * 2; cl += 2) { 850 PetscInt point = closure[cl], depth, dof, off, d, p; 851 852 if ((point < pStart) || (point >= pEnd)) continue; 853 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 854 if (!dof) continue; 855 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 856 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 858 for (p = 0; p < dof / dim; ++p) { 859 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 860 for (d = 0; d < dim; ++d) { 861 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 862 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 863 } 864 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 865 } 866 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 867 } 868 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 869 PetscCall(PetscViewerASCIIPopTab(viewer)); 870 } 871 PetscCall(VecRestoreArrayRead(coordinates, &a)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 typedef enum { 876 CS_CARTESIAN, 877 CS_POLAR, 878 CS_CYLINDRICAL, 879 CS_SPHERICAL 880 } CoordSystem; 881 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 882 883 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 884 { 885 PetscInt i; 886 887 PetscFunctionBegin; 888 if (dim > 3) { 889 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 890 } else { 891 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 892 893 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 894 switch (cs) { 895 case CS_CARTESIAN: 896 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 897 break; 898 case CS_POLAR: 899 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 900 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 901 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 902 break; 903 case CS_CYLINDRICAL: 904 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 905 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 906 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 907 trcoords[2] = coords[2]; 908 break; 909 case CS_SPHERICAL: 910 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 911 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 912 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 913 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 914 break; 915 } 916 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 917 } 918 PetscFunctionReturn(PETSC_SUCCESS); 919 } 920 921 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 922 { 923 DM_Plex *mesh = (DM_Plex *)dm->data; 924 DM cdm, cdmCell; 925 PetscSection coordSection, coordSectionCell; 926 Vec coordinates, coordinatesCell; 927 PetscViewerFormat format; 928 929 PetscFunctionBegin; 930 PetscCall(PetscViewerGetFormat(viewer, &format)); 931 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 932 const char *name; 933 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 934 PetscInt pStart, pEnd, p, numLabels, l; 935 PetscMPIInt rank, size; 936 937 PetscCall(DMGetCoordinateDM(dm, &cdm)); 938 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 939 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 940 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 941 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 942 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 943 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 944 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 945 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 946 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 947 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 948 PetscCall(DMGetDimension(dm, &dim)); 949 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 950 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 951 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 952 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 953 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 954 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 955 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 956 for (p = pStart; p < pEnd; ++p) { 957 PetscInt dof, off, s; 958 959 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 960 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 961 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 962 } 963 PetscCall(PetscViewerFlush(viewer)); 964 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 965 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 966 for (p = pStart; p < pEnd; ++p) { 967 PetscInt dof, off, c; 968 969 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 970 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 971 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 972 } 973 PetscCall(PetscViewerFlush(viewer)); 974 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 975 if (coordSection && coordinates) { 976 CoordSystem cs = CS_CARTESIAN; 977 const PetscScalar *array, *arrayCell = NULL; 978 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 979 PetscMPIInt rank; 980 const char *name; 981 982 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 983 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 984 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 985 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 986 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 987 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 988 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 989 pStart = PetscMin(pvStart, pcStart); 990 pEnd = PetscMax(pvEnd, pcEnd); 991 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 992 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 994 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 995 996 PetscCall(VecGetArrayRead(coordinates, &array)); 997 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 998 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 999 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1000 for (p = pStart; p < pEnd; ++p) { 1001 PetscInt dof, off; 1002 1003 if (p >= pvStart && p < pvEnd) { 1004 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1005 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1006 if (dof) { 1007 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1008 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1009 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1010 } 1011 } 1012 if (cdmCell && p >= pcStart && p < pcEnd) { 1013 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1014 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1015 if (dof) { 1016 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1017 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1018 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1019 } 1020 } 1021 } 1022 PetscCall(PetscViewerFlush(viewer)); 1023 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1024 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1025 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1026 } 1027 PetscCall(DMGetNumLabels(dm, &numLabels)); 1028 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1029 for (l = 0; l < numLabels; ++l) { 1030 DMLabel label; 1031 PetscBool isdepth; 1032 const char *name; 1033 1034 PetscCall(DMGetLabelName(dm, l, &name)); 1035 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1036 if (isdepth) continue; 1037 PetscCall(DMGetLabel(dm, name, &label)); 1038 PetscCall(DMLabelView(label, viewer)); 1039 } 1040 if (size > 1) { 1041 PetscSF sf; 1042 1043 PetscCall(DMGetPointSF(dm, &sf)); 1044 PetscCall(PetscSFView(sf, viewer)); 1045 } 1046 if (mesh->periodic.face_sfs) 1047 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1048 PetscCall(PetscViewerFlush(viewer)); 1049 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1050 const char *name, *color; 1051 const char *defcolors[3] = {"gray", "orange", "green"}; 1052 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1053 char lname[PETSC_MAX_PATH_LEN]; 1054 PetscReal scale = 2.0; 1055 PetscReal tikzscale = 1.0; 1056 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1057 double tcoords[3]; 1058 PetscScalar *coords; 1059 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 1060 PetscMPIInt rank, size; 1061 char **names, **colors, **lcolors; 1062 PetscBool flg, lflg; 1063 PetscBT wp = NULL; 1064 PetscInt pEnd, pStart; 1065 1066 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1069 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1070 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1071 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1072 PetscCall(DMGetDimension(dm, &dim)); 1073 PetscCall(DMPlexGetDepth(dm, &depth)); 1074 PetscCall(DMGetNumLabels(dm, &numLabels)); 1075 numLabels = PetscMax(numLabels, 10); 1076 numColors = 10; 1077 numLColors = 10; 1078 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1080 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1081 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1082 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1083 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1084 n = 4; 1085 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1086 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1087 n = 4; 1088 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1089 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1090 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1091 if (!useLabels) numLabels = 0; 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1093 if (!useColors) { 1094 numColors = 3; 1095 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1096 } 1097 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1098 if (!useColors) { 1099 numLColors = 4; 1100 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1101 } 1102 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1103 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1104 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1105 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1106 if (depth < dim) plotEdges = PETSC_FALSE; 1107 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1108 1109 /* filter points with labelvalue != labeldefaultvalue */ 1110 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1112 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1113 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1114 if (lflg) { 1115 DMLabel lbl; 1116 1117 PetscCall(DMGetLabel(dm, lname, &lbl)); 1118 if (lbl) { 1119 PetscInt val, defval; 1120 1121 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1122 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1123 for (c = pStart; c < pEnd; c++) { 1124 PetscInt *closure = NULL; 1125 PetscInt closureSize; 1126 1127 PetscCall(DMLabelGetValue(lbl, c, &val)); 1128 if (val == defval) continue; 1129 1130 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1131 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1132 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1133 } 1134 } 1135 } 1136 1137 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1138 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1139 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1140 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1141 \\documentclass[tikz]{standalone}\n\n\ 1142 \\usepackage{pgflibraryshapes}\n\ 1143 \\usetikzlibrary{backgrounds}\n\ 1144 \\usetikzlibrary{arrows}\n\ 1145 \\begin{document}\n")); 1146 if (size > 1) { 1147 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1148 for (p = 0; p < size; ++p) { 1149 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1150 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1151 } 1152 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1153 } 1154 if (drawHasse) { 1155 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1156 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1169 } 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1171 1172 /* Plot vertices */ 1173 PetscCall(VecGetArray(coordinates, &coords)); 1174 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1175 for (v = vStart; v < vEnd; ++v) { 1176 PetscInt off, dof, d; 1177 PetscBool isLabeled = PETSC_FALSE; 1178 1179 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1180 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1181 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1182 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1183 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1184 for (d = 0; d < dof; ++d) { 1185 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1186 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1187 } 1188 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1189 if (dim == 3) { 1190 PetscReal tmp = tcoords[1]; 1191 tcoords[1] = tcoords[2]; 1192 tcoords[2] = -tmp; 1193 } 1194 for (d = 0; d < dof; ++d) { 1195 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1196 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1197 } 1198 if (drawHasse) color = colors[0 % numColors]; 1199 else color = colors[rank % numColors]; 1200 for (l = 0; l < numLabels; ++l) { 1201 PetscInt val; 1202 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1203 if (val >= 0) { 1204 color = lcolors[l % numLColors]; 1205 isLabeled = PETSC_TRUE; 1206 break; 1207 } 1208 } 1209 if (drawNumbers[0]) { 1210 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1211 } else if (drawColors[0]) { 1212 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1213 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1214 } 1215 PetscCall(VecRestoreArray(coordinates, &coords)); 1216 PetscCall(PetscViewerFlush(viewer)); 1217 /* Plot edges */ 1218 if (plotEdges) { 1219 PetscCall(VecGetArray(coordinates, &coords)); 1220 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1221 for (e = eStart; e < eEnd; ++e) { 1222 const PetscInt *cone; 1223 PetscInt coneSize, offA, offB, dof, d; 1224 1225 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1226 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1227 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1228 PetscCall(DMPlexGetCone(dm, e, &cone)); 1229 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1230 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1231 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1232 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1233 for (d = 0; d < dof; ++d) { 1234 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1235 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1236 } 1237 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1238 if (dim == 3) { 1239 PetscReal tmp = tcoords[1]; 1240 tcoords[1] = tcoords[2]; 1241 tcoords[2] = -tmp; 1242 } 1243 for (d = 0; d < dof; ++d) { 1244 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1245 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1246 } 1247 if (drawHasse) color = colors[1 % numColors]; 1248 else color = colors[rank % numColors]; 1249 for (l = 0; l < numLabels; ++l) { 1250 PetscInt val; 1251 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1252 if (val >= 0) { 1253 color = lcolors[l % numLColors]; 1254 break; 1255 } 1256 } 1257 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1258 } 1259 PetscCall(VecRestoreArray(coordinates, &coords)); 1260 PetscCall(PetscViewerFlush(viewer)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1262 } 1263 /* Plot cells */ 1264 if (dim == 3 || !drawNumbers[1]) { 1265 for (e = eStart; e < eEnd; ++e) { 1266 const PetscInt *cone; 1267 1268 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1269 color = colors[rank % numColors]; 1270 for (l = 0; l < numLabels; ++l) { 1271 PetscInt val; 1272 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1273 if (val >= 0) { 1274 color = lcolors[l % numLColors]; 1275 break; 1276 } 1277 } 1278 PetscCall(DMPlexGetCone(dm, e, &cone)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1280 } 1281 } else { 1282 DMPolytopeType ct; 1283 1284 /* Drawing a 2D polygon */ 1285 for (c = cStart; c < cEnd; ++c) { 1286 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1287 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1288 if (DMPolytopeTypeIsHybrid(ct)) { 1289 const PetscInt *cone; 1290 PetscInt coneSize, e; 1291 1292 PetscCall(DMPlexGetCone(dm, c, &cone)); 1293 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1294 for (e = 0; e < coneSize; ++e) { 1295 const PetscInt *econe; 1296 1297 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1298 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1299 } 1300 } else { 1301 PetscInt *closure = NULL; 1302 PetscInt closureSize, Nv = 0, v; 1303 1304 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1305 for (p = 0; p < closureSize * 2; p += 2) { 1306 const PetscInt point = closure[p]; 1307 1308 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1309 } 1310 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1311 for (v = 0; v <= Nv; ++v) { 1312 const PetscInt vertex = closure[v % Nv]; 1313 1314 if (v > 0) { 1315 if (plotEdges) { 1316 const PetscInt *edge; 1317 PetscInt endpoints[2], ne; 1318 1319 endpoints[0] = closure[v - 1]; 1320 endpoints[1] = vertex; 1321 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1322 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1323 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1324 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1325 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1326 } 1327 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1328 } 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1330 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1331 } 1332 } 1333 } 1334 for (c = cStart; c < cEnd; ++c) { 1335 double ccoords[3] = {0.0, 0.0, 0.0}; 1336 PetscBool isLabeled = PETSC_FALSE; 1337 PetscScalar *cellCoords = NULL; 1338 const PetscScalar *array; 1339 PetscInt numCoords, cdim, d; 1340 PetscBool isDG; 1341 1342 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1343 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1344 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1345 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1346 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1347 for (p = 0; p < numCoords / cdim; ++p) { 1348 for (d = 0; d < cdim; ++d) { 1349 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1350 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1351 } 1352 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1353 if (cdim == 3) { 1354 PetscReal tmp = tcoords[1]; 1355 tcoords[1] = tcoords[2]; 1356 tcoords[2] = -tmp; 1357 } 1358 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1359 } 1360 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1361 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1362 for (d = 0; d < cdim; ++d) { 1363 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1364 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1365 } 1366 if (drawHasse) color = colors[depth % numColors]; 1367 else color = colors[rank % numColors]; 1368 for (l = 0; l < numLabels; ++l) { 1369 PetscInt val; 1370 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1371 if (val >= 0) { 1372 color = lcolors[l % numLColors]; 1373 isLabeled = PETSC_TRUE; 1374 break; 1375 } 1376 } 1377 if (drawNumbers[dim]) { 1378 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1379 } else if (drawColors[dim]) { 1380 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1381 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1382 } 1383 if (drawHasse) { 1384 color = colors[depth % numColors]; 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1388 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1389 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1390 1391 color = colors[1 % numColors]; 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1397 1398 color = colors[0 % numColors]; 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1404 1405 for (p = pStart; p < pEnd; ++p) { 1406 const PetscInt *cone; 1407 PetscInt coneSize, cp; 1408 1409 PetscCall(DMPlexGetCone(dm, p, &cone)); 1410 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1411 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1412 } 1413 } 1414 PetscCall(PetscViewerFlush(viewer)); 1415 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1418 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1419 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1420 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1421 PetscCall(PetscFree3(names, colors, lcolors)); 1422 PetscCall(PetscBTDestroy(&wp)); 1423 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1424 Vec cown, acown; 1425 VecScatter sct; 1426 ISLocalToGlobalMapping g2l; 1427 IS gid, acis; 1428 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1429 MPI_Group ggroup, ngroup; 1430 PetscScalar *array, nid; 1431 const PetscInt *idxs; 1432 PetscInt *idxs2, *start, *adjacency, *work; 1433 PetscInt64 lm[3], gm[3]; 1434 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1435 PetscMPIInt d1, d2, rank; 1436 1437 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1438 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1439 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1440 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1441 #endif 1442 if (ncomm != MPI_COMM_NULL) { 1443 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1444 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1445 d1 = 0; 1446 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1447 nid = d2; 1448 PetscCallMPI(MPI_Group_free(&ggroup)); 1449 PetscCallMPI(MPI_Group_free(&ngroup)); 1450 PetscCallMPI(MPI_Comm_free(&ncomm)); 1451 } else nid = 0.0; 1452 1453 /* Get connectivity */ 1454 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1455 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1456 1457 /* filter overlapped local cells */ 1458 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1459 PetscCall(ISGetIndices(gid, &idxs)); 1460 PetscCall(ISGetLocalSize(gid, &cum)); 1461 PetscCall(PetscMalloc1(cum, &idxs2)); 1462 for (c = cStart, cum = 0; c < cEnd; c++) { 1463 if (idxs[c - cStart] < 0) continue; 1464 idxs2[cum++] = idxs[c - cStart]; 1465 } 1466 PetscCall(ISRestoreIndices(gid, &idxs)); 1467 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1468 PetscCall(ISDestroy(&gid)); 1469 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1470 1471 /* support for node-aware cell locality */ 1472 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1473 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1474 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1475 PetscCall(VecGetArray(cown, &array)); 1476 for (c = 0; c < numVertices; c++) array[c] = nid; 1477 PetscCall(VecRestoreArray(cown, &array)); 1478 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1479 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1480 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1481 PetscCall(ISDestroy(&acis)); 1482 PetscCall(VecScatterDestroy(&sct)); 1483 PetscCall(VecDestroy(&cown)); 1484 1485 /* compute edgeCut */ 1486 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1487 PetscCall(PetscMalloc1(cum, &work)); 1488 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1489 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1490 PetscCall(ISDestroy(&gid)); 1491 PetscCall(VecGetArray(acown, &array)); 1492 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1493 PetscInt totl; 1494 1495 totl = start[c + 1] - start[c]; 1496 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1497 for (i = 0; i < totl; i++) { 1498 if (work[i] < 0) { 1499 ect += 1; 1500 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1501 } 1502 } 1503 } 1504 PetscCall(PetscFree(work)); 1505 PetscCall(VecRestoreArray(acown, &array)); 1506 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1507 lm[1] = -numVertices; 1508 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1510 lm[0] = ect; /* edgeCut */ 1511 lm[1] = ectn; /* node-aware edgeCut */ 1512 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1513 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1514 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1515 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1516 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1517 #else 1518 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1519 #endif 1520 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1521 PetscCall(PetscFree(start)); 1522 PetscCall(PetscFree(adjacency)); 1523 PetscCall(VecDestroy(&acown)); 1524 } else { 1525 const char *name; 1526 PetscInt *sizes, *hybsizes, *ghostsizes; 1527 PetscInt locDepth, depth, cellHeight, dim, d; 1528 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1529 PetscInt numLabels, l, maxSize = 17; 1530 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1531 MPI_Comm comm; 1532 PetscMPIInt size, rank; 1533 1534 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1535 PetscCallMPI(MPI_Comm_size(comm, &size)); 1536 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1537 PetscCall(DMGetDimension(dm, &dim)); 1538 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1539 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1540 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1541 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1542 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1543 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1544 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1545 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1546 gcNum = gcEnd - gcStart; 1547 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1548 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1549 for (d = 0; d <= depth; d++) { 1550 PetscInt Nc[2] = {0, 0}, ict; 1551 1552 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1553 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1554 ict = ct0; 1555 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1556 ct0 = (DMPolytopeType)ict; 1557 for (p = pStart; p < pEnd; ++p) { 1558 DMPolytopeType ct; 1559 1560 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1561 if (ct == ct0) ++Nc[0]; 1562 else ++Nc[1]; 1563 } 1564 if (size < maxSize) { 1565 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1566 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1567 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1568 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1569 for (p = 0; p < size; ++p) { 1570 if (rank == 0) { 1571 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1572 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1573 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1574 } 1575 } 1576 } else { 1577 PetscInt locMinMax[2]; 1578 1579 locMinMax[0] = Nc[0] + Nc[1]; 1580 locMinMax[1] = Nc[0] + Nc[1]; 1581 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1582 locMinMax[0] = Nc[1]; 1583 locMinMax[1] = Nc[1]; 1584 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1585 if (d == depth) { 1586 locMinMax[0] = gcNum; 1587 locMinMax[1] = gcNum; 1588 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1589 } 1590 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1591 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1592 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1593 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1594 } 1595 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1596 } 1597 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1598 { 1599 const PetscReal *maxCell; 1600 const PetscReal *L; 1601 PetscBool localized; 1602 1603 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1604 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1605 if (L || localized) { 1606 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1607 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1608 if (L) { 1609 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1610 for (d = 0; d < dim; ++d) { 1611 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1612 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1613 } 1614 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1615 } 1616 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1617 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1618 } 1619 } 1620 PetscCall(DMGetNumLabels(dm, &numLabels)); 1621 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1622 for (l = 0; l < numLabels; ++l) { 1623 DMLabel label; 1624 const char *name; 1625 IS valueIS; 1626 const PetscInt *values; 1627 PetscInt numValues, v; 1628 1629 PetscCall(DMGetLabelName(dm, l, &name)); 1630 PetscCall(DMGetLabel(dm, name, &label)); 1631 PetscCall(DMLabelGetNumValues(label, &numValues)); 1632 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1633 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1634 PetscCall(ISGetIndices(valueIS, &values)); 1635 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1636 for (v = 0; v < numValues; ++v) { 1637 PetscInt size; 1638 1639 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1640 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1641 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1642 } 1643 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1644 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1645 PetscCall(ISRestoreIndices(valueIS, &values)); 1646 PetscCall(ISDestroy(&valueIS)); 1647 } 1648 { 1649 char **labelNames; 1650 PetscInt Nl = numLabels; 1651 PetscBool flg; 1652 1653 PetscCall(PetscMalloc1(Nl, &labelNames)); 1654 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1655 for (l = 0; l < Nl; ++l) { 1656 DMLabel label; 1657 1658 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1659 if (flg) { 1660 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1661 PetscCall(DMLabelView(label, viewer)); 1662 } 1663 PetscCall(PetscFree(labelNames[l])); 1664 } 1665 PetscCall(PetscFree(labelNames)); 1666 } 1667 /* If no fields are specified, people do not want to see adjacency */ 1668 if (dm->Nf) { 1669 PetscInt f; 1670 1671 for (f = 0; f < dm->Nf; ++f) { 1672 const char *name; 1673 1674 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1675 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1676 PetscCall(PetscViewerASCIIPushTab(viewer)); 1677 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1678 if (dm->fields[f].adjacency[0]) { 1679 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1680 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1681 } else { 1682 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1683 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1684 } 1685 PetscCall(PetscViewerASCIIPopTab(viewer)); 1686 } 1687 } 1688 PetscCall(DMGetCoarseDM(dm, &cdm)); 1689 if (cdm) { 1690 PetscCall(PetscViewerASCIIPushTab(viewer)); 1691 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1692 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1693 PetscCall(PetscViewerASCIIPopTab(viewer)); 1694 } 1695 } 1696 PetscFunctionReturn(PETSC_SUCCESS); 1697 } 1698 1699 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1700 { 1701 DMPolytopeType ct; 1702 PetscMPIInt rank; 1703 PetscInt cdim; 1704 1705 PetscFunctionBegin; 1706 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1707 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1708 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1709 switch (ct) { 1710 case DM_POLYTOPE_SEGMENT: 1711 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1712 switch (cdim) { 1713 case 1: { 1714 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1715 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1716 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1718 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1719 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1720 } break; 1721 case 2: { 1722 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1723 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1724 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1725 1726 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1727 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1728 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1729 } break; 1730 default: 1731 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1732 } 1733 break; 1734 case DM_POLYTOPE_TRIANGLE: 1735 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1738 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1739 break; 1740 case DM_POLYTOPE_QUADRILATERAL: 1741 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1742 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1746 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1747 break; 1748 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1749 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1750 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1754 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1755 break; 1756 case DM_POLYTOPE_FV_GHOST: 1757 break; 1758 default: 1759 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1760 } 1761 PetscFunctionReturn(PETSC_SUCCESS); 1762 } 1763 1764 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1765 { 1766 PetscReal centroid[2] = {0., 0.}; 1767 PetscMPIInt rank; 1768 PetscInt fillColor; 1769 1770 PetscFunctionBegin; 1771 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1772 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1773 for (PetscInt v = 0; v < Nv; ++v) { 1774 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1775 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1776 } 1777 for (PetscInt e = 0; e < Nv; ++e) { 1778 refCoords[0] = refVertices[e * 2 + 0]; 1779 refCoords[1] = refVertices[e * 2 + 1]; 1780 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1781 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1782 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1783 } 1784 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1785 for (PetscInt d = 0; d < edgeDiv; ++d) { 1786 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1787 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1788 } 1789 } 1790 PetscFunctionReturn(PETSC_SUCCESS); 1791 } 1792 1793 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1794 { 1795 DMPolytopeType ct; 1796 1797 PetscFunctionBegin; 1798 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1799 switch (ct) { 1800 case DM_POLYTOPE_TRIANGLE: { 1801 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1802 1803 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1804 } break; 1805 case DM_POLYTOPE_QUADRILATERAL: { 1806 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1807 1808 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1809 } break; 1810 default: 1811 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1812 } 1813 PetscFunctionReturn(PETSC_SUCCESS); 1814 } 1815 1816 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1817 { 1818 PetscDraw draw; 1819 DM cdm; 1820 PetscSection coordSection; 1821 Vec coordinates; 1822 PetscReal xyl[3], xyr[3]; 1823 PetscReal *refCoords, *edgeCoords; 1824 PetscBool isnull, drawAffine; 1825 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1826 1827 PetscFunctionBegin; 1828 PetscCall(DMGetCoordinateDim(dm, &dim)); 1829 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1830 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1831 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1832 edgeDiv = cDegree + 1; 1833 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1834 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1835 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1836 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1837 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1838 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1839 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1840 1841 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1842 PetscCall(PetscDrawIsNull(draw, &isnull)); 1843 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1844 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1845 1846 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1847 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1848 PetscCall(PetscDrawClear(draw)); 1849 1850 for (c = cStart; c < cEnd; ++c) { 1851 PetscScalar *coords = NULL; 1852 const PetscScalar *coords_arr; 1853 PetscInt numCoords; 1854 PetscBool isDG; 1855 1856 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1857 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1858 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1859 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1860 } 1861 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1862 PetscCall(PetscDrawFlush(draw)); 1863 PetscCall(PetscDrawPause(draw)); 1864 PetscCall(PetscDrawSave(draw)); 1865 PetscFunctionReturn(PETSC_SUCCESS); 1866 } 1867 1868 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1869 { 1870 DM odm = dm, rdm = dm, cdm; 1871 PetscFE fe; 1872 PetscSpace sp; 1873 PetscClassId id; 1874 PetscInt degree; 1875 PetscBool hoView = PETSC_TRUE; 1876 1877 PetscFunctionBegin; 1878 PetscObjectOptionsBegin((PetscObject)dm); 1879 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1880 PetscOptionsEnd(); 1881 PetscCall(PetscObjectReference((PetscObject)dm)); 1882 *hdm = dm; 1883 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1884 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1885 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1886 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1887 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1888 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1889 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1890 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1891 DM cdm, rcdm; 1892 Mat In; 1893 Vec cl, rcl; 1894 1895 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1896 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1897 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1898 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1899 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1900 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1901 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1902 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1903 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1904 PetscCall(MatMult(In, cl, rcl)); 1905 PetscCall(MatDestroy(&In)); 1906 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1907 PetscCall(DMDestroy(&odm)); 1908 odm = rdm; 1909 } 1910 *hdm = rdm; 1911 PetscFunctionReturn(PETSC_SUCCESS); 1912 } 1913 1914 #if defined(PETSC_HAVE_EXODUSII) 1915 #include <exodusII.h> 1916 #include <petscviewerexodusii.h> 1917 #endif 1918 1919 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1920 { 1921 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1922 char name[PETSC_MAX_PATH_LEN]; 1923 1924 PetscFunctionBegin; 1925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1926 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1927 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1928 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1929 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1930 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1931 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1932 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1933 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1934 if (iascii) { 1935 PetscViewerFormat format; 1936 PetscCall(PetscViewerGetFormat(viewer, &format)); 1937 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1938 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1939 } else if (ishdf5) { 1940 #if defined(PETSC_HAVE_HDF5) 1941 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1942 #else 1943 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1944 #endif 1945 } else if (isvtk) { 1946 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1947 } else if (isdraw) { 1948 DM hdm; 1949 1950 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1951 PetscCall(DMPlexView_Draw(hdm, viewer)); 1952 PetscCall(DMDestroy(&hdm)); 1953 } else if (isglvis) { 1954 PetscCall(DMPlexView_GLVis(dm, viewer)); 1955 #if defined(PETSC_HAVE_EXODUSII) 1956 } else if (isexodus) { 1957 /* 1958 exodusII requires that all sets be part of exactly one cell set. 1959 If the dm does not have a "Cell Sets" label defined, we create one 1960 with ID 1, containing all cells. 1961 Note that if the Cell Sets label is defined but does not cover all cells, 1962 we may still have a problem. This should probably be checked here or in the viewer; 1963 */ 1964 PetscInt numCS; 1965 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1966 if (!numCS) { 1967 PetscInt cStart, cEnd, c; 1968 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1969 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1970 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1971 } 1972 PetscCall(DMView_PlexExodusII(dm, viewer)); 1973 #endif 1974 #if defined(PETSC_HAVE_CGNS) 1975 } else if (iscgns) { 1976 PetscCall(DMView_PlexCGNS(dm, viewer)); 1977 #endif 1978 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1979 /* Optionally view the partition */ 1980 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1981 if (flg) { 1982 Vec ranks; 1983 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1984 PetscCall(VecView(ranks, viewer)); 1985 PetscCall(VecDestroy(&ranks)); 1986 } 1987 /* Optionally view a label */ 1988 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1989 if (flg) { 1990 DMLabel label; 1991 Vec val; 1992 1993 PetscCall(DMGetLabel(dm, name, &label)); 1994 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1995 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1996 PetscCall(VecView(val, viewer)); 1997 PetscCall(VecDestroy(&val)); 1998 } 1999 PetscFunctionReturn(PETSC_SUCCESS); 2000 } 2001 2002 /*@ 2003 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2004 2005 Collective 2006 2007 Input Parameters: 2008 + dm - The `DM` whose topology is to be saved 2009 - viewer - The `PetscViewer` to save it in 2010 2011 Level: advanced 2012 2013 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2014 @*/ 2015 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2016 { 2017 PetscBool ishdf5; 2018 2019 PetscFunctionBegin; 2020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2021 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2022 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2023 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2024 if (ishdf5) { 2025 #if defined(PETSC_HAVE_HDF5) 2026 PetscViewerFormat format; 2027 PetscCall(PetscViewerGetFormat(viewer, &format)); 2028 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2029 IS globalPointNumbering; 2030 2031 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2032 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2033 PetscCall(ISDestroy(&globalPointNumbering)); 2034 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2035 #else 2036 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2037 #endif 2038 } 2039 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2040 PetscFunctionReturn(PETSC_SUCCESS); 2041 } 2042 2043 /*@ 2044 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2045 2046 Collective 2047 2048 Input Parameters: 2049 + dm - The `DM` whose coordinates are to be saved 2050 - viewer - The `PetscViewer` for saving 2051 2052 Level: advanced 2053 2054 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2055 @*/ 2056 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2057 { 2058 PetscBool ishdf5; 2059 2060 PetscFunctionBegin; 2061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2062 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2063 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2064 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2065 if (ishdf5) { 2066 #if defined(PETSC_HAVE_HDF5) 2067 PetscViewerFormat format; 2068 PetscCall(PetscViewerGetFormat(viewer, &format)); 2069 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2070 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2071 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2072 #else 2073 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2074 #endif 2075 } 2076 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2077 PetscFunctionReturn(PETSC_SUCCESS); 2078 } 2079 2080 /*@ 2081 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2082 2083 Collective 2084 2085 Input Parameters: 2086 + dm - The `DM` whose labels are to be saved 2087 - viewer - The `PetscViewer` for saving 2088 2089 Level: advanced 2090 2091 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2092 @*/ 2093 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2094 { 2095 PetscBool ishdf5; 2096 2097 PetscFunctionBegin; 2098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2099 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2100 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2101 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2102 if (ishdf5) { 2103 #if defined(PETSC_HAVE_HDF5) 2104 IS globalPointNumbering; 2105 PetscViewerFormat format; 2106 2107 PetscCall(PetscViewerGetFormat(viewer, &format)); 2108 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2109 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2110 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2111 PetscCall(ISDestroy(&globalPointNumbering)); 2112 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2113 #else 2114 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2115 #endif 2116 } 2117 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2118 PetscFunctionReturn(PETSC_SUCCESS); 2119 } 2120 2121 /*@ 2122 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2123 2124 Collective 2125 2126 Input Parameters: 2127 + dm - The `DM` that contains the topology on which the section to be saved is defined 2128 . viewer - The `PetscViewer` for saving 2129 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2130 2131 Level: advanced 2132 2133 Notes: 2134 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (`dm`) points. When the topology (`dm`) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 2135 2136 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2137 2138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2139 @*/ 2140 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2141 { 2142 PetscBool ishdf5; 2143 2144 PetscFunctionBegin; 2145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2146 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2147 if (!sectiondm) sectiondm = dm; 2148 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2149 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2150 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2151 if (ishdf5) { 2152 #if defined(PETSC_HAVE_HDF5) 2153 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2154 #else 2155 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2156 #endif 2157 } 2158 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2159 PetscFunctionReturn(PETSC_SUCCESS); 2160 } 2161 2162 /*@ 2163 DMPlexGlobalVectorView - Saves a global vector 2164 2165 Collective 2166 2167 Input Parameters: 2168 + dm - The `DM` that represents the topology 2169 . viewer - The `PetscViewer` to save data with 2170 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2171 - vec - The global vector to be saved 2172 2173 Level: advanced 2174 2175 Notes: 2176 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2177 2178 Calling sequence: 2179 .vb 2180 DMCreate(PETSC_COMM_WORLD, &dm); 2181 DMSetType(dm, DMPLEX); 2182 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2183 DMClone(dm, §iondm); 2184 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2185 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2186 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2187 PetscSectionSetChart(section, pStart, pEnd); 2188 PetscSectionSetUp(section); 2189 DMSetLocalSection(sectiondm, section); 2190 PetscSectionDestroy(§ion); 2191 DMGetGlobalVector(sectiondm, &vec); 2192 PetscObjectSetName((PetscObject)vec, "vec_name"); 2193 DMPlexTopologyView(dm, viewer); 2194 DMPlexSectionView(dm, viewer, sectiondm); 2195 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2196 DMRestoreGlobalVector(sectiondm, &vec); 2197 DMDestroy(§iondm); 2198 DMDestroy(&dm); 2199 .ve 2200 2201 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2202 @*/ 2203 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2204 { 2205 PetscBool ishdf5; 2206 2207 PetscFunctionBegin; 2208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2209 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2210 if (!sectiondm) sectiondm = dm; 2211 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2212 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2213 /* Check consistency */ 2214 { 2215 PetscSection section; 2216 PetscBool includesConstraints; 2217 PetscInt m, m1; 2218 2219 PetscCall(VecGetLocalSize(vec, &m1)); 2220 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2221 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2222 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2223 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2224 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2225 } 2226 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2227 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2228 if (ishdf5) { 2229 #if defined(PETSC_HAVE_HDF5) 2230 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2231 #else 2232 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2233 #endif 2234 } 2235 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2236 PetscFunctionReturn(PETSC_SUCCESS); 2237 } 2238 2239 /*@ 2240 DMPlexLocalVectorView - Saves a local vector 2241 2242 Collective 2243 2244 Input Parameters: 2245 + dm - The `DM` that represents the topology 2246 . viewer - The `PetscViewer` to save data with 2247 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2248 - vec - The local vector to be saved 2249 2250 Level: advanced 2251 2252 Note: 2253 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2254 2255 Calling sequence: 2256 .vb 2257 DMCreate(PETSC_COMM_WORLD, &dm); 2258 DMSetType(dm, DMPLEX); 2259 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2260 DMClone(dm, §iondm); 2261 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2262 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2263 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2264 PetscSectionSetChart(section, pStart, pEnd); 2265 PetscSectionSetUp(section); 2266 DMSetLocalSection(sectiondm, section); 2267 DMGetLocalVector(sectiondm, &vec); 2268 PetscObjectSetName((PetscObject)vec, "vec_name"); 2269 DMPlexTopologyView(dm, viewer); 2270 DMPlexSectionView(dm, viewer, sectiondm); 2271 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2272 DMRestoreLocalVector(sectiondm, &vec); 2273 DMDestroy(§iondm); 2274 DMDestroy(&dm); 2275 .ve 2276 2277 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2278 @*/ 2279 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2280 { 2281 PetscBool ishdf5; 2282 2283 PetscFunctionBegin; 2284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2285 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2286 if (!sectiondm) sectiondm = dm; 2287 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2288 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2289 /* Check consistency */ 2290 { 2291 PetscSection section; 2292 PetscBool includesConstraints; 2293 PetscInt m, m1; 2294 2295 PetscCall(VecGetLocalSize(vec, &m1)); 2296 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2297 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2298 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2299 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2300 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2301 } 2302 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2303 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2304 if (ishdf5) { 2305 #if defined(PETSC_HAVE_HDF5) 2306 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2307 #else 2308 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2309 #endif 2310 } 2311 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2312 PetscFunctionReturn(PETSC_SUCCESS); 2313 } 2314 2315 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2316 { 2317 PetscBool ishdf5; 2318 2319 PetscFunctionBegin; 2320 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2321 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2322 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2323 if (ishdf5) { 2324 #if defined(PETSC_HAVE_HDF5) 2325 PetscViewerFormat format; 2326 PetscCall(PetscViewerGetFormat(viewer, &format)); 2327 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2328 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2329 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2330 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2331 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2332 PetscFunctionReturn(PETSC_SUCCESS); 2333 #else 2334 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2335 #endif 2336 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2337 } 2338 2339 /*@ 2340 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2341 2342 Collective 2343 2344 Input Parameters: 2345 + dm - The `DM` into which the topology is loaded 2346 - viewer - The `PetscViewer` for the saved topology 2347 2348 Output Parameter: 2349 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded 2350 2351 Level: advanced 2352 2353 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2354 `PetscViewer`, `PetscSF` 2355 @*/ 2356 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2357 { 2358 PetscBool ishdf5; 2359 2360 PetscFunctionBegin; 2361 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2362 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2363 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2364 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2365 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2366 if (ishdf5) { 2367 #if defined(PETSC_HAVE_HDF5) 2368 PetscViewerFormat format; 2369 PetscCall(PetscViewerGetFormat(viewer, &format)); 2370 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2371 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2372 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2373 #else 2374 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2375 #endif 2376 } 2377 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2378 PetscFunctionReturn(PETSC_SUCCESS); 2379 } 2380 2381 /*@ 2382 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2383 2384 Collective 2385 2386 Input Parameters: 2387 + dm - The `DM` into which the coordinates are loaded 2388 . viewer - The `PetscViewer` for the saved coordinates 2389 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2390 2391 Level: advanced 2392 2393 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2394 `PetscSF`, `PetscViewer` 2395 @*/ 2396 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2397 { 2398 PetscBool ishdf5; 2399 2400 PetscFunctionBegin; 2401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2402 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2403 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2404 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2405 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2406 if (ishdf5) { 2407 #if defined(PETSC_HAVE_HDF5) 2408 PetscViewerFormat format; 2409 PetscCall(PetscViewerGetFormat(viewer, &format)); 2410 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2411 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2412 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2413 #else 2414 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2415 #endif 2416 } 2417 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2418 PetscFunctionReturn(PETSC_SUCCESS); 2419 } 2420 2421 /*@ 2422 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2423 2424 Collective 2425 2426 Input Parameters: 2427 + dm - The `DM` into which the labels are loaded 2428 . viewer - The `PetscViewer` for the saved labels 2429 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2430 2431 Level: advanced 2432 2433 Note: 2434 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2435 2436 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2437 `PetscSF`, `PetscViewer` 2438 @*/ 2439 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2440 { 2441 PetscBool ishdf5; 2442 2443 PetscFunctionBegin; 2444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2445 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2446 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2447 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2448 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2449 if (ishdf5) { 2450 #if defined(PETSC_HAVE_HDF5) 2451 PetscViewerFormat format; 2452 2453 PetscCall(PetscViewerGetFormat(viewer, &format)); 2454 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2455 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2456 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2457 #else 2458 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2459 #endif 2460 } 2461 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2462 PetscFunctionReturn(PETSC_SUCCESS); 2463 } 2464 2465 /*@ 2466 DMPlexSectionLoad - Loads section into a `DMPLEX` 2467 2468 Collective 2469 2470 Input Parameters: 2471 + dm - The `DM` that represents the topology 2472 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2473 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2474 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2475 2476 Output Parameters: 2477 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2478 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2479 2480 Level: advanced 2481 2482 Notes: 2483 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2484 2485 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2486 2487 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2488 2489 Example using 2 processes: 2490 .vb 2491 NX (number of points on dm): 4 2492 sectionA : the on-disk section 2493 vecA : a vector associated with sectionA 2494 sectionB : sectiondm's local section constructed in this function 2495 vecB (local) : a vector associated with sectiondm's local section 2496 vecB (global) : a vector associated with sectiondm's global section 2497 2498 rank 0 rank 1 2499 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2500 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2501 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2502 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2503 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2504 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2505 sectionB->atlasDof : 1 0 1 | 1 3 2506 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2507 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2508 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2509 .ve 2510 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2511 2512 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2513 @*/ 2514 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2515 { 2516 PetscBool ishdf5; 2517 2518 PetscFunctionBegin; 2519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2520 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2521 if (!sectiondm) sectiondm = dm; 2522 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2523 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2524 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2525 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2526 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2527 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2528 if (ishdf5) { 2529 #if defined(PETSC_HAVE_HDF5) 2530 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2531 #else 2532 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2533 #endif 2534 } 2535 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2536 PetscFunctionReturn(PETSC_SUCCESS); 2537 } 2538 2539 /*@ 2540 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2541 2542 Collective 2543 2544 Input Parameters: 2545 + dm - The `DM` that represents the topology 2546 . viewer - The `PetscViewer` that represents the on-disk vector data 2547 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2548 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2549 - vec - The global vector to set values of 2550 2551 Level: advanced 2552 2553 Notes: 2554 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2555 2556 Calling sequence: 2557 .vb 2558 DMCreate(PETSC_COMM_WORLD, &dm); 2559 DMSetType(dm, DMPLEX); 2560 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2561 DMPlexTopologyLoad(dm, viewer, &sfX); 2562 DMClone(dm, §iondm); 2563 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2564 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2565 DMGetGlobalVector(sectiondm, &vec); 2566 PetscObjectSetName((PetscObject)vec, "vec_name"); 2567 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2568 DMRestoreGlobalVector(sectiondm, &vec); 2569 PetscSFDestroy(&gsf); 2570 PetscSFDestroy(&sfX); 2571 DMDestroy(§iondm); 2572 DMDestroy(&dm); 2573 .ve 2574 2575 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2576 `PetscSF`, `PetscViewer` 2577 @*/ 2578 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2579 { 2580 PetscBool ishdf5; 2581 2582 PetscFunctionBegin; 2583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2584 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2585 if (!sectiondm) sectiondm = dm; 2586 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2587 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2588 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2589 /* Check consistency */ 2590 { 2591 PetscSection section; 2592 PetscBool includesConstraints; 2593 PetscInt m, m1; 2594 2595 PetscCall(VecGetLocalSize(vec, &m1)); 2596 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2597 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2598 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2599 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2600 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2601 } 2602 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2603 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2604 if (ishdf5) { 2605 #if defined(PETSC_HAVE_HDF5) 2606 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2607 #else 2608 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2609 #endif 2610 } 2611 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2612 PetscFunctionReturn(PETSC_SUCCESS); 2613 } 2614 2615 /*@ 2616 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2617 2618 Collective 2619 2620 Input Parameters: 2621 + dm - The `DM` that represents the topology 2622 . viewer - The `PetscViewer` that represents the on-disk vector data 2623 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2624 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2625 - vec - The local vector to set values of 2626 2627 Level: advanced 2628 2629 Notes: 2630 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2631 2632 Calling sequence: 2633 .vb 2634 DMCreate(PETSC_COMM_WORLD, &dm); 2635 DMSetType(dm, DMPLEX); 2636 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2637 DMPlexTopologyLoad(dm, viewer, &sfX); 2638 DMClone(dm, §iondm); 2639 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2640 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2641 DMGetLocalVector(sectiondm, &vec); 2642 PetscObjectSetName((PetscObject)vec, "vec_name"); 2643 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2644 DMRestoreLocalVector(sectiondm, &vec); 2645 PetscSFDestroy(&lsf); 2646 PetscSFDestroy(&sfX); 2647 DMDestroy(§iondm); 2648 DMDestroy(&dm); 2649 .ve 2650 2651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2652 `PetscSF`, `PetscViewer` 2653 @*/ 2654 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2655 { 2656 PetscBool ishdf5; 2657 2658 PetscFunctionBegin; 2659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2660 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2661 if (!sectiondm) sectiondm = dm; 2662 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2663 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2664 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2665 /* Check consistency */ 2666 { 2667 PetscSection section; 2668 PetscBool includesConstraints; 2669 PetscInt m, m1; 2670 2671 PetscCall(VecGetLocalSize(vec, &m1)); 2672 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2673 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2674 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2675 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2676 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2677 } 2678 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2679 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2680 if (ishdf5) { 2681 #if defined(PETSC_HAVE_HDF5) 2682 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2683 #else 2684 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2685 #endif 2686 } 2687 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2688 PetscFunctionReturn(PETSC_SUCCESS); 2689 } 2690 2691 PetscErrorCode DMDestroy_Plex(DM dm) 2692 { 2693 DM_Plex *mesh = (DM_Plex *)dm->data; 2694 2695 PetscFunctionBegin; 2696 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2697 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2698 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2699 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2700 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2701 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2702 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2703 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2704 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2705 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2706 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2707 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2708 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2709 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2710 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2711 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2712 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2713 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2714 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2715 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2716 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2717 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2718 PetscCall(PetscFree(mesh->cones)); 2719 PetscCall(PetscFree(mesh->coneOrientations)); 2720 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2721 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2722 PetscCall(PetscFree(mesh->supports)); 2723 PetscCall(PetscFree(mesh->cellTypes)); 2724 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2725 PetscCall(PetscFree(mesh->tetgenOpts)); 2726 PetscCall(PetscFree(mesh->triangleOpts)); 2727 PetscCall(PetscFree(mesh->transformType)); 2728 PetscCall(PetscFree(mesh->distributionName)); 2729 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2730 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2731 PetscCall(ISDestroy(&mesh->subpointIS)); 2732 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2733 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2734 if (mesh->periodic.face_sfs) { 2735 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2736 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2737 } 2738 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2739 if (mesh->periodic.periodic_points) { 2740 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2741 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2742 } 2743 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2744 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2745 PetscCall(ISDestroy(&mesh->anchorIS)); 2746 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2747 PetscCall(PetscFree(mesh->parents)); 2748 PetscCall(PetscFree(mesh->childIDs)); 2749 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2750 PetscCall(PetscFree(mesh->children)); 2751 PetscCall(DMDestroy(&mesh->referenceTree)); 2752 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2753 PetscCall(PetscFree(mesh->neighbors)); 2754 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2755 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2756 PetscCall(PetscFree(mesh)); 2757 PetscFunctionReturn(PETSC_SUCCESS); 2758 } 2759 2760 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2761 { 2762 PetscSection sectionGlobal, sectionLocal; 2763 PetscInt bs = -1, mbs; 2764 PetscInt localSize, localStart = 0; 2765 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2766 MatType mtype; 2767 ISLocalToGlobalMapping ltog; 2768 2769 PetscFunctionBegin; 2770 PetscCall(MatInitializePackage()); 2771 mtype = dm->mattype; 2772 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2773 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2774 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2775 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2776 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2777 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2778 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2779 PetscCall(MatSetType(*J, mtype)); 2780 PetscCall(MatSetFromOptions(*J)); 2781 PetscCall(MatGetBlockSize(*J, &mbs)); 2782 if (mbs > 1) bs = mbs; 2783 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2784 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2785 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2786 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2787 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2788 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2789 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2790 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2791 if (!isShell) { 2792 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2793 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2794 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2795 2796 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2797 2798 PetscCall(PetscCalloc1(localSize, &pblocks)); 2799 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2800 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2801 for (p = pStart; p < pEnd; ++p) { 2802 switch (dm->blocking_type) { 2803 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2804 PetscInt bdof, offset; 2805 2806 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2807 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2808 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2809 if (dof > 0) { 2810 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2811 // Signal block concatenation 2812 if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof); 2813 } 2814 dof = dof < 0 ? -(dof + 1) : dof; 2815 bdof = cdof && (dof - cdof) ? 1 : dof; 2816 if (dof) { 2817 if (bs < 0) { 2818 bs = bdof; 2819 } else if (bs != bdof) { 2820 bs = 1; 2821 } 2822 } 2823 } break; 2824 case DM_BLOCKING_FIELD_NODE: { 2825 for (PetscInt field = 0; field < num_fields; field++) { 2826 PetscInt num_comp, bdof, offset; 2827 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2828 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2829 if (dof < 0) continue; 2830 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2831 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2832 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); 2833 PetscInt num_nodes = dof / num_comp; 2834 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2835 // Handle possibly constant block size (unlikely) 2836 bdof = cdof && (dof - cdof) ? 1 : dof; 2837 if (dof) { 2838 if (bs < 0) { 2839 bs = bdof; 2840 } else if (bs != bdof) { 2841 bs = 1; 2842 } 2843 } 2844 } 2845 } break; 2846 } 2847 } 2848 /* Must have same blocksize on all procs (some might have no points) */ 2849 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2850 bsLocal[1] = bs; 2851 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2852 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2853 else bs = bsMinMax[0]; 2854 bs = PetscMax(1, bs); 2855 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2856 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2857 PetscCall(MatSetBlockSize(*J, bs)); 2858 PetscCall(MatSetUp(*J)); 2859 } else { 2860 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2861 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2862 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2863 } 2864 if (pblocks) { // Consolidate blocks 2865 PetscInt nblocks = 0; 2866 pblocks[0] = PetscAbs(pblocks[0]); 2867 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2868 if (pblocks[i] == 0) continue; 2869 // Negative block size indicates the blocks should be concatenated 2870 if (pblocks[i] < 0) { 2871 pblocks[i] = -pblocks[i]; 2872 pblocks[nblocks - 1] += pblocks[i]; 2873 } else { 2874 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2875 } 2876 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]); 2877 } 2878 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2879 } 2880 PetscCall(PetscFree(pblocks)); 2881 } 2882 PetscCall(MatSetDM(*J, dm)); 2883 PetscFunctionReturn(PETSC_SUCCESS); 2884 } 2885 2886 /*@ 2887 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2888 2889 Not Collective 2890 2891 Input Parameter: 2892 . dm - The `DMPLEX` 2893 2894 Output Parameter: 2895 . subsection - The subdomain section 2896 2897 Level: developer 2898 2899 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2900 @*/ 2901 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2902 { 2903 DM_Plex *mesh = (DM_Plex *)dm->data; 2904 2905 PetscFunctionBegin; 2906 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2907 if (!mesh->subdomainSection) { 2908 PetscSection section; 2909 PetscSF sf; 2910 2911 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2912 PetscCall(DMGetLocalSection(dm, §ion)); 2913 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2914 PetscCall(PetscSFDestroy(&sf)); 2915 } 2916 *subsection = mesh->subdomainSection; 2917 PetscFunctionReturn(PETSC_SUCCESS); 2918 } 2919 2920 /*@ 2921 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2922 2923 Not Collective 2924 2925 Input Parameter: 2926 . dm - The `DMPLEX` 2927 2928 Output Parameters: 2929 + pStart - The first mesh point 2930 - pEnd - The upper bound for mesh points 2931 2932 Level: beginner 2933 2934 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2935 @*/ 2936 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2937 { 2938 DM_Plex *mesh = (DM_Plex *)dm->data; 2939 2940 PetscFunctionBegin; 2941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2942 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2943 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2944 PetscFunctionReturn(PETSC_SUCCESS); 2945 } 2946 2947 /*@ 2948 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2949 2950 Not Collective 2951 2952 Input Parameters: 2953 + dm - The `DMPLEX` 2954 . pStart - The first mesh point 2955 - pEnd - The upper bound for mesh points 2956 2957 Level: beginner 2958 2959 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2960 @*/ 2961 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2962 { 2963 DM_Plex *mesh = (DM_Plex *)dm->data; 2964 2965 PetscFunctionBegin; 2966 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2967 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2968 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2969 PetscCall(PetscFree(mesh->cellTypes)); 2970 PetscFunctionReturn(PETSC_SUCCESS); 2971 } 2972 2973 /*@ 2974 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2975 2976 Not Collective 2977 2978 Input Parameters: 2979 + dm - The `DMPLEX` 2980 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2981 2982 Output Parameter: 2983 . size - The cone size for point `p` 2984 2985 Level: beginner 2986 2987 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2988 @*/ 2989 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2990 { 2991 DM_Plex *mesh = (DM_Plex *)dm->data; 2992 2993 PetscFunctionBegin; 2994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2995 PetscAssertPointer(size, 3); 2996 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2997 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2998 PetscFunctionReturn(PETSC_SUCCESS); 2999 } 3000 3001 /*@ 3002 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3003 3004 Not Collective 3005 3006 Input Parameters: 3007 + dm - The `DMPLEX` 3008 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3009 - size - The cone size for point `p` 3010 3011 Level: beginner 3012 3013 Note: 3014 This should be called after `DMPlexSetChart()`. 3015 3016 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3017 @*/ 3018 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3019 { 3020 DM_Plex *mesh = (DM_Plex *)dm->data; 3021 3022 PetscFunctionBegin; 3023 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3024 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3025 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3026 PetscFunctionReturn(PETSC_SUCCESS); 3027 } 3028 3029 /*@C 3030 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3031 3032 Not Collective 3033 3034 Input Parameters: 3035 + dm - The `DMPLEX` 3036 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3037 3038 Output Parameter: 3039 . cone - An array of points which are on the in-edges for point `p` 3040 3041 Level: beginner 3042 3043 Fortran Notes: 3044 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3045 `DMPlexRestoreCone()` is not needed/available in C. 3046 3047 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3048 @*/ 3049 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3050 { 3051 DM_Plex *mesh = (DM_Plex *)dm->data; 3052 PetscInt off; 3053 3054 PetscFunctionBegin; 3055 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3056 PetscAssertPointer(cone, 3); 3057 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3058 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3059 PetscFunctionReturn(PETSC_SUCCESS); 3060 } 3061 3062 /*@C 3063 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3064 3065 Not Collective 3066 3067 Input Parameters: 3068 + dm - The `DMPLEX` 3069 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3070 3071 Output Parameters: 3072 + pConesSection - `PetscSection` describing the layout of `pCones` 3073 - pCones - An array of points which are on the in-edges for the point set `p` 3074 3075 Level: intermediate 3076 3077 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3078 @*/ 3079 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3080 { 3081 PetscSection cs, newcs; 3082 PetscInt *cones; 3083 PetscInt *newarr = NULL; 3084 PetscInt n; 3085 3086 PetscFunctionBegin; 3087 PetscCall(DMPlexGetCones(dm, &cones)); 3088 PetscCall(DMPlexGetConeSection(dm, &cs)); 3089 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3090 if (pConesSection) *pConesSection = newcs; 3091 if (pCones) { 3092 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3093 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3094 } 3095 PetscFunctionReturn(PETSC_SUCCESS); 3096 } 3097 3098 /*@ 3099 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3100 3101 Not Collective 3102 3103 Input Parameters: 3104 + dm - The `DMPLEX` 3105 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3106 3107 Output Parameter: 3108 . expandedPoints - An array of vertices recursively expanded from input points 3109 3110 Level: advanced 3111 3112 Notes: 3113 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3114 3115 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3116 3117 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3118 `DMPlexGetDepth()`, `IS` 3119 @*/ 3120 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3121 { 3122 IS *expandedPointsAll; 3123 PetscInt depth; 3124 3125 PetscFunctionBegin; 3126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3127 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3128 PetscAssertPointer(expandedPoints, 3); 3129 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3130 *expandedPoints = expandedPointsAll[0]; 3131 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3132 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3133 PetscFunctionReturn(PETSC_SUCCESS); 3134 } 3135 3136 /*@ 3137 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). 3138 3139 Not Collective 3140 3141 Input Parameters: 3142 + dm - The `DMPLEX` 3143 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3144 3145 Output Parameters: 3146 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3147 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3148 - sections - (optional) An array of sections which describe mappings from points to their cone points 3149 3150 Level: advanced 3151 3152 Notes: 3153 Like `DMPlexGetConeTuple()` but recursive. 3154 3155 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. 3156 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3157 3158 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\: 3159 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3160 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3161 3162 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3163 `DMPlexGetDepth()`, `PetscSection`, `IS` 3164 @*/ 3165 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3166 { 3167 const PetscInt *arr0 = NULL, *cone = NULL; 3168 PetscInt *arr = NULL, *newarr = NULL; 3169 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3170 IS *expandedPoints_; 3171 PetscSection *sections_; 3172 3173 PetscFunctionBegin; 3174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3175 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3176 if (depth) PetscAssertPointer(depth, 3); 3177 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3178 if (sections) PetscAssertPointer(sections, 5); 3179 PetscCall(ISGetLocalSize(points, &n)); 3180 PetscCall(ISGetIndices(points, &arr0)); 3181 PetscCall(DMPlexGetDepth(dm, &depth_)); 3182 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3183 PetscCall(PetscCalloc1(depth_, §ions_)); 3184 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3185 for (d = depth_ - 1; d >= 0; d--) { 3186 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3187 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3188 for (i = 0; i < n; i++) { 3189 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3190 if (arr[i] >= start && arr[i] < end) { 3191 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3192 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3193 } else { 3194 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3195 } 3196 } 3197 PetscCall(PetscSectionSetUp(sections_[d])); 3198 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3199 PetscCall(PetscMalloc1(newn, &newarr)); 3200 for (i = 0; i < n; i++) { 3201 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3202 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3203 if (cn > 1) { 3204 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3205 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3206 } else { 3207 newarr[co] = arr[i]; 3208 } 3209 } 3210 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3211 arr = newarr; 3212 n = newn; 3213 } 3214 PetscCall(ISRestoreIndices(points, &arr0)); 3215 *depth = depth_; 3216 if (expandedPoints) *expandedPoints = expandedPoints_; 3217 else { 3218 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3219 PetscCall(PetscFree(expandedPoints_)); 3220 } 3221 if (sections) *sections = sections_; 3222 else { 3223 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3224 PetscCall(PetscFree(sections_)); 3225 } 3226 PetscFunctionReturn(PETSC_SUCCESS); 3227 } 3228 3229 /*@ 3230 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3231 3232 Not Collective 3233 3234 Input Parameters: 3235 + dm - The `DMPLEX` 3236 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3237 3238 Output Parameters: 3239 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3240 . expandedPoints - (optional) An array of recursively expanded cones 3241 - sections - (optional) An array of sections which describe mappings from points to their cone points 3242 3243 Level: advanced 3244 3245 Note: 3246 See `DMPlexGetConeRecursive()` 3247 3248 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3249 `DMPlexGetDepth()`, `IS`, `PetscSection` 3250 @*/ 3251 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3252 { 3253 PetscInt d, depth_; 3254 3255 PetscFunctionBegin; 3256 PetscCall(DMPlexGetDepth(dm, &depth_)); 3257 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3258 if (depth) *depth = 0; 3259 if (expandedPoints) { 3260 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3261 PetscCall(PetscFree(*expandedPoints)); 3262 } 3263 if (sections) { 3264 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3265 PetscCall(PetscFree(*sections)); 3266 } 3267 PetscFunctionReturn(PETSC_SUCCESS); 3268 } 3269 3270 /*@ 3271 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 3272 3273 Not Collective 3274 3275 Input Parameters: 3276 + dm - The `DMPLEX` 3277 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3278 - cone - An array of points which are on the in-edges for point `p` 3279 3280 Level: beginner 3281 3282 Note: 3283 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3284 3285 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3286 @*/ 3287 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3288 { 3289 DM_Plex *mesh = (DM_Plex *)dm->data; 3290 PetscInt dof, off, c; 3291 3292 PetscFunctionBegin; 3293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3294 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3295 if (dof) PetscAssertPointer(cone, 3); 3296 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3297 if (PetscDefined(USE_DEBUG)) { 3298 PetscInt pStart, pEnd; 3299 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3300 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); 3301 for (c = 0; c < dof; ++c) { 3302 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); 3303 mesh->cones[off + c] = cone[c]; 3304 } 3305 } else { 3306 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3307 } 3308 PetscFunctionReturn(PETSC_SUCCESS); 3309 } 3310 3311 /*@C 3312 DMPlexGetConeOrientation - Return 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 3320 Output Parameter: 3321 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3322 integer giving the prescription for cone traversal. 3323 3324 Level: beginner 3325 3326 Note: 3327 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3328 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3329 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3330 with the identity. 3331 3332 Fortran Notes: 3333 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3334 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3335 3336 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3337 @*/ 3338 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3339 { 3340 DM_Plex *mesh = (DM_Plex *)dm->data; 3341 PetscInt off; 3342 3343 PetscFunctionBegin; 3344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3345 if (PetscDefined(USE_DEBUG)) { 3346 PetscInt dof; 3347 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3348 if (dof) PetscAssertPointer(coneOrientation, 3); 3349 } 3350 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3351 3352 *coneOrientation = &mesh->coneOrientations[off]; 3353 PetscFunctionReturn(PETSC_SUCCESS); 3354 } 3355 3356 /*@ 3357 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3358 3359 Not Collective 3360 3361 Input Parameters: 3362 + dm - The `DMPLEX` 3363 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3364 - coneOrientation - An array of orientations 3365 3366 Level: beginner 3367 3368 Notes: 3369 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3370 3371 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3372 3373 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3374 @*/ 3375 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3376 { 3377 DM_Plex *mesh = (DM_Plex *)dm->data; 3378 PetscInt pStart, pEnd; 3379 PetscInt dof, off, c; 3380 3381 PetscFunctionBegin; 3382 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3383 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3384 if (dof) PetscAssertPointer(coneOrientation, 3); 3385 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3386 if (PetscDefined(USE_DEBUG)) { 3387 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3388 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); 3389 for (c = 0; c < dof; ++c) { 3390 PetscInt cdof, o = coneOrientation[c]; 3391 3392 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3393 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); 3394 mesh->coneOrientations[off + c] = o; 3395 } 3396 } else { 3397 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3398 } 3399 PetscFunctionReturn(PETSC_SUCCESS); 3400 } 3401 3402 /*@ 3403 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3404 3405 Not Collective 3406 3407 Input Parameters: 3408 + dm - The `DMPLEX` 3409 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3410 . conePos - The local index in the cone where the point should be put 3411 - conePoint - The mesh point to insert 3412 3413 Level: beginner 3414 3415 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3416 @*/ 3417 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3418 { 3419 DM_Plex *mesh = (DM_Plex *)dm->data; 3420 PetscInt pStart, pEnd; 3421 PetscInt dof, off; 3422 3423 PetscFunctionBegin; 3424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3425 if (PetscDefined(USE_DEBUG)) { 3426 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3427 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); 3428 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); 3429 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3430 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); 3431 } 3432 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3433 mesh->cones[off + conePos] = conePoint; 3434 PetscFunctionReturn(PETSC_SUCCESS); 3435 } 3436 3437 /*@ 3438 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3439 3440 Not Collective 3441 3442 Input Parameters: 3443 + dm - The `DMPLEX` 3444 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3445 . conePos - The local index in the cone where the point should be put 3446 - coneOrientation - The point orientation to insert 3447 3448 Level: beginner 3449 3450 Note: 3451 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3452 3453 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3454 @*/ 3455 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3456 { 3457 DM_Plex *mesh = (DM_Plex *)dm->data; 3458 PetscInt pStart, pEnd; 3459 PetscInt dof, off; 3460 3461 PetscFunctionBegin; 3462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3463 if (PetscDefined(USE_DEBUG)) { 3464 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3465 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); 3466 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3467 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); 3468 } 3469 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3470 mesh->coneOrientations[off + conePos] = coneOrientation; 3471 PetscFunctionReturn(PETSC_SUCCESS); 3472 } 3473 3474 /*@C 3475 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3476 3477 Not collective 3478 3479 Input Parameters: 3480 + dm - The DMPlex 3481 - p - The point, which must lie in the chart set with DMPlexSetChart() 3482 3483 Output Parameters: 3484 + cone - An array of points which are on the in-edges for point `p` 3485 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3486 integer giving the prescription for cone traversal. 3487 3488 Level: beginner 3489 3490 Notes: 3491 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3492 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3493 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3494 with the identity. 3495 3496 Fortran Notes: 3497 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3498 `DMPlexRestoreCone()` is not needed/available in C. 3499 3500 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3501 @*/ 3502 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3503 { 3504 DM_Plex *mesh = (DM_Plex *)dm->data; 3505 3506 PetscFunctionBegin; 3507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3508 if (mesh->tr) { 3509 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3510 } else { 3511 PetscInt off; 3512 if (PetscDefined(USE_DEBUG)) { 3513 PetscInt dof; 3514 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3515 if (dof) { 3516 if (cone) PetscAssertPointer(cone, 3); 3517 if (ornt) PetscAssertPointer(ornt, 4); 3518 } 3519 } 3520 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3521 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3522 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3523 } 3524 PetscFunctionReturn(PETSC_SUCCESS); 3525 } 3526 3527 /*@C 3528 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3529 3530 Not Collective 3531 3532 Input Parameters: 3533 + dm - The DMPlex 3534 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3535 . cone - An array of points which are on the in-edges for point p 3536 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3537 integer giving the prescription for cone traversal. 3538 3539 Level: beginner 3540 3541 Notes: 3542 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3543 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3544 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3545 with the identity. 3546 3547 Fortran Notes: 3548 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3549 `DMPlexRestoreCone()` is not needed/available in C. 3550 3551 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3552 @*/ 3553 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3554 { 3555 DM_Plex *mesh = (DM_Plex *)dm->data; 3556 3557 PetscFunctionBegin; 3558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3559 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3560 PetscFunctionReturn(PETSC_SUCCESS); 3561 } 3562 3563 /*@ 3564 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3565 3566 Not Collective 3567 3568 Input Parameters: 3569 + dm - The `DMPLEX` 3570 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3571 3572 Output Parameter: 3573 . size - The support size for point `p` 3574 3575 Level: beginner 3576 3577 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3578 @*/ 3579 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3580 { 3581 DM_Plex *mesh = (DM_Plex *)dm->data; 3582 3583 PetscFunctionBegin; 3584 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3585 PetscAssertPointer(size, 3); 3586 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3587 PetscFunctionReturn(PETSC_SUCCESS); 3588 } 3589 3590 /*@ 3591 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3592 3593 Not Collective 3594 3595 Input Parameters: 3596 + dm - The `DMPLEX` 3597 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3598 - size - The support size for point `p` 3599 3600 Level: beginner 3601 3602 Note: 3603 This should be called after `DMPlexSetChart()`. 3604 3605 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3606 @*/ 3607 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3608 { 3609 DM_Plex *mesh = (DM_Plex *)dm->data; 3610 3611 PetscFunctionBegin; 3612 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3613 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3614 PetscFunctionReturn(PETSC_SUCCESS); 3615 } 3616 3617 /*@C 3618 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3619 3620 Not Collective 3621 3622 Input Parameters: 3623 + dm - The `DMPLEX` 3624 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3625 3626 Output Parameter: 3627 . support - An array of points which are on the out-edges for point `p` 3628 3629 Level: beginner 3630 3631 Fortran Notes: 3632 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3633 `DMPlexRestoreSupport()` is not needed/available in C. 3634 3635 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3636 @*/ 3637 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3638 { 3639 DM_Plex *mesh = (DM_Plex *)dm->data; 3640 PetscInt off; 3641 3642 PetscFunctionBegin; 3643 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3644 PetscAssertPointer(support, 3); 3645 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3646 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3647 PetscFunctionReturn(PETSC_SUCCESS); 3648 } 3649 3650 /*@ 3651 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3652 3653 Not Collective 3654 3655 Input Parameters: 3656 + dm - The `DMPLEX` 3657 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3658 - support - An array of points which are on the out-edges for point `p` 3659 3660 Level: beginner 3661 3662 Note: 3663 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3664 3665 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3666 @*/ 3667 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3668 { 3669 DM_Plex *mesh = (DM_Plex *)dm->data; 3670 PetscInt pStart, pEnd; 3671 PetscInt dof, off, c; 3672 3673 PetscFunctionBegin; 3674 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3675 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3676 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3677 if (dof) PetscAssertPointer(support, 3); 3678 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3679 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); 3680 for (c = 0; c < dof; ++c) { 3681 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); 3682 mesh->supports[off + c] = support[c]; 3683 } 3684 PetscFunctionReturn(PETSC_SUCCESS); 3685 } 3686 3687 /*@ 3688 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3689 3690 Not Collective 3691 3692 Input Parameters: 3693 + dm - The `DMPLEX` 3694 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3695 . supportPos - The local index in the cone where the point should be put 3696 - supportPoint - The mesh point to insert 3697 3698 Level: beginner 3699 3700 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3701 @*/ 3702 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3703 { 3704 DM_Plex *mesh = (DM_Plex *)dm->data; 3705 PetscInt pStart, pEnd; 3706 PetscInt dof, off; 3707 3708 PetscFunctionBegin; 3709 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3710 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3711 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3712 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3713 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); 3714 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); 3715 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); 3716 mesh->supports[off + supportPos] = supportPoint; 3717 PetscFunctionReturn(PETSC_SUCCESS); 3718 } 3719 3720 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3721 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3722 { 3723 switch (ct) { 3724 case DM_POLYTOPE_SEGMENT: 3725 if (o == -1) return -2; 3726 break; 3727 case DM_POLYTOPE_TRIANGLE: 3728 if (o == -3) return -1; 3729 if (o == -2) return -3; 3730 if (o == -1) return -2; 3731 break; 3732 case DM_POLYTOPE_QUADRILATERAL: 3733 if (o == -4) return -2; 3734 if (o == -3) return -1; 3735 if (o == -2) return -4; 3736 if (o == -1) return -3; 3737 break; 3738 default: 3739 return o; 3740 } 3741 return o; 3742 } 3743 3744 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3745 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3746 { 3747 switch (ct) { 3748 case DM_POLYTOPE_SEGMENT: 3749 if ((o == -2) || (o == 1)) return -1; 3750 if (o == -1) return 0; 3751 break; 3752 case DM_POLYTOPE_TRIANGLE: 3753 if (o == -3) return -2; 3754 if (o == -2) return -1; 3755 if (o == -1) return -3; 3756 break; 3757 case DM_POLYTOPE_QUADRILATERAL: 3758 if (o == -4) return -2; 3759 if (o == -3) return -1; 3760 if (o == -2) return -4; 3761 if (o == -1) return -3; 3762 break; 3763 default: 3764 return o; 3765 } 3766 return o; 3767 } 3768 3769 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3770 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3771 { 3772 PetscInt pStart, pEnd, p; 3773 3774 PetscFunctionBegin; 3775 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3776 for (p = pStart; p < pEnd; ++p) { 3777 const PetscInt *cone, *ornt; 3778 PetscInt coneSize, c; 3779 3780 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3781 PetscCall(DMPlexGetCone(dm, p, &cone)); 3782 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3783 for (c = 0; c < coneSize; ++c) { 3784 DMPolytopeType ct; 3785 const PetscInt o = ornt[c]; 3786 3787 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3788 switch (ct) { 3789 case DM_POLYTOPE_SEGMENT: 3790 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3791 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3792 break; 3793 case DM_POLYTOPE_TRIANGLE: 3794 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3795 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3796 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3797 break; 3798 case DM_POLYTOPE_QUADRILATERAL: 3799 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3800 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3801 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3802 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3803 break; 3804 default: 3805 break; 3806 } 3807 } 3808 } 3809 PetscFunctionReturn(PETSC_SUCCESS); 3810 } 3811 3812 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3813 { 3814 DM_Plex *mesh = (DM_Plex *)dm->data; 3815 3816 PetscFunctionBeginHot; 3817 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3818 if (useCone) { 3819 PetscCall(DMPlexGetConeSize(dm, p, size)); 3820 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3821 } else { 3822 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3823 PetscCall(DMPlexGetSupport(dm, p, arr)); 3824 } 3825 } else { 3826 if (useCone) { 3827 const PetscSection s = mesh->coneSection; 3828 const PetscInt ps = p - s->pStart; 3829 const PetscInt off = s->atlasOff[ps]; 3830 3831 *size = s->atlasDof[ps]; 3832 *arr = mesh->cones + off; 3833 *ornt = mesh->coneOrientations + off; 3834 } else { 3835 const PetscSection s = mesh->supportSection; 3836 const PetscInt ps = p - s->pStart; 3837 const PetscInt off = s->atlasOff[ps]; 3838 3839 *size = s->atlasDof[ps]; 3840 *arr = mesh->supports + off; 3841 } 3842 } 3843 PetscFunctionReturn(PETSC_SUCCESS); 3844 } 3845 3846 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3847 { 3848 DM_Plex *mesh = (DM_Plex *)dm->data; 3849 3850 PetscFunctionBeginHot; 3851 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3852 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3853 } 3854 PetscFunctionReturn(PETSC_SUCCESS); 3855 } 3856 3857 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3858 { 3859 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3860 PetscInt *closure; 3861 const PetscInt *tmp = NULL, *tmpO = NULL; 3862 PetscInt off = 0, tmpSize, t; 3863 3864 PetscFunctionBeginHot; 3865 if (ornt) { 3866 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3867 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; 3868 } 3869 if (*points) { 3870 closure = *points; 3871 } else { 3872 PetscInt maxConeSize, maxSupportSize; 3873 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3874 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3875 } 3876 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3877 if (ct == DM_POLYTOPE_UNKNOWN) { 3878 closure[off++] = p; 3879 closure[off++] = 0; 3880 for (t = 0; t < tmpSize; ++t) { 3881 closure[off++] = tmp[t]; 3882 closure[off++] = tmpO ? tmpO[t] : 0; 3883 } 3884 } else { 3885 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3886 3887 /* We assume that cells with a valid type have faces with a valid type */ 3888 closure[off++] = p; 3889 closure[off++] = ornt; 3890 for (t = 0; t < tmpSize; ++t) { 3891 DMPolytopeType ft; 3892 3893 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3894 closure[off++] = tmp[arr[t]]; 3895 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3896 } 3897 } 3898 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3899 if (numPoints) *numPoints = tmpSize + 1; 3900 if (points) *points = closure; 3901 PetscFunctionReturn(PETSC_SUCCESS); 3902 } 3903 3904 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3905 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3906 { 3907 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3908 const PetscInt *cone, *ornt; 3909 PetscInt *pts, *closure = NULL; 3910 DMPolytopeType ft; 3911 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3912 PetscInt dim, coneSize, c, d, clSize, cl; 3913 3914 PetscFunctionBeginHot; 3915 PetscCall(DMGetDimension(dm, &dim)); 3916 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3917 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3918 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3919 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3920 maxSize = PetscMax(coneSeries, supportSeries); 3921 if (*points) { 3922 pts = *points; 3923 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3924 c = 0; 3925 pts[c++] = point; 3926 pts[c++] = o; 3927 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3928 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3929 for (cl = 0; cl < clSize * 2; cl += 2) { 3930 pts[c++] = closure[cl]; 3931 pts[c++] = closure[cl + 1]; 3932 } 3933 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3934 for (cl = 0; cl < clSize * 2; cl += 2) { 3935 pts[c++] = closure[cl]; 3936 pts[c++] = closure[cl + 1]; 3937 } 3938 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3939 for (d = 2; d < coneSize; ++d) { 3940 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3941 pts[c++] = cone[arr[d * 2 + 0]]; 3942 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3943 } 3944 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3945 if (dim >= 3) { 3946 for (d = 2; d < coneSize; ++d) { 3947 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3948 const PetscInt *fcone, *fornt; 3949 PetscInt fconeSize, fc, i; 3950 3951 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3952 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3953 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3954 for (fc = 0; fc < fconeSize; ++fc) { 3955 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3956 const PetscInt co = farr[fc * 2 + 1]; 3957 3958 for (i = 0; i < c; i += 2) 3959 if (pts[i] == cp) break; 3960 if (i == c) { 3961 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3962 pts[c++] = cp; 3963 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3964 } 3965 } 3966 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3967 } 3968 } 3969 *numPoints = c / 2; 3970 *points = pts; 3971 PetscFunctionReturn(PETSC_SUCCESS); 3972 } 3973 3974 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3975 { 3976 DMPolytopeType ct; 3977 PetscInt *closure, *fifo; 3978 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3979 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3980 PetscInt depth, maxSize; 3981 3982 PetscFunctionBeginHot; 3983 PetscCall(DMPlexGetDepth(dm, &depth)); 3984 if (depth == 1) { 3985 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3986 PetscFunctionReturn(PETSC_SUCCESS); 3987 } 3988 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3989 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; 3990 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3991 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3992 PetscFunctionReturn(PETSC_SUCCESS); 3993 } 3994 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3995 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3996 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3997 maxSize = PetscMax(coneSeries, supportSeries); 3998 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3999 if (*points) { 4000 closure = *points; 4001 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4002 closure[closureSize++] = p; 4003 closure[closureSize++] = ornt; 4004 fifo[fifoSize++] = p; 4005 fifo[fifoSize++] = ornt; 4006 fifo[fifoSize++] = ct; 4007 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4008 while (fifoSize - fifoStart) { 4009 const PetscInt q = fifo[fifoStart++]; 4010 const PetscInt o = fifo[fifoStart++]; 4011 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4012 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4013 const PetscInt *tmp, *tmpO = NULL; 4014 PetscInt tmpSize, t; 4015 4016 if (PetscDefined(USE_DEBUG)) { 4017 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4018 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); 4019 } 4020 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4021 for (t = 0; t < tmpSize; ++t) { 4022 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4023 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4024 const PetscInt cp = tmp[ip]; 4025 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4026 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4027 PetscInt c; 4028 4029 /* Check for duplicate */ 4030 for (c = 0; c < closureSize; c += 2) { 4031 if (closure[c] == cp) break; 4032 } 4033 if (c == closureSize) { 4034 closure[closureSize++] = cp; 4035 closure[closureSize++] = co; 4036 fifo[fifoSize++] = cp; 4037 fifo[fifoSize++] = co; 4038 fifo[fifoSize++] = ct; 4039 } 4040 } 4041 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4042 } 4043 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4044 if (numPoints) *numPoints = closureSize / 2; 4045 if (points) *points = closure; 4046 PetscFunctionReturn(PETSC_SUCCESS); 4047 } 4048 4049 /*@C 4050 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4051 4052 Not Collective 4053 4054 Input Parameters: 4055 + dm - The `DMPLEX` 4056 . p - The mesh point 4057 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4058 4059 Input/Output Parameter: 4060 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4061 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4062 4063 Output Parameter: 4064 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4065 4066 Level: beginner 4067 4068 Note: 4069 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4070 4071 Fortran Notes: 4072 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4073 4074 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4075 @*/ 4076 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4077 { 4078 PetscFunctionBeginHot; 4079 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4080 if (numPoints) PetscAssertPointer(numPoints, 4); 4081 if (points) PetscAssertPointer(points, 5); 4082 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4083 PetscFunctionReturn(PETSC_SUCCESS); 4084 } 4085 4086 /*@C 4087 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4088 4089 Not Collective 4090 4091 Input Parameters: 4092 + dm - The `DMPLEX` 4093 . p - The mesh point 4094 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4095 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4096 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4097 4098 Level: beginner 4099 4100 Note: 4101 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4102 4103 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4104 @*/ 4105 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4106 { 4107 PetscFunctionBeginHot; 4108 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4109 if (numPoints) *numPoints = 0; 4110 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4111 PetscFunctionReturn(PETSC_SUCCESS); 4112 } 4113 4114 /*@ 4115 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4116 4117 Not Collective 4118 4119 Input Parameter: 4120 . dm - The `DMPLEX` 4121 4122 Output Parameters: 4123 + maxConeSize - The maximum number of in-edges 4124 - maxSupportSize - The maximum number of out-edges 4125 4126 Level: beginner 4127 4128 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4129 @*/ 4130 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4131 { 4132 DM_Plex *mesh = (DM_Plex *)dm->data; 4133 4134 PetscFunctionBegin; 4135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4136 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4137 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4138 PetscFunctionReturn(PETSC_SUCCESS); 4139 } 4140 4141 PetscErrorCode DMSetUp_Plex(DM dm) 4142 { 4143 DM_Plex *mesh = (DM_Plex *)dm->data; 4144 PetscInt size, maxSupportSize; 4145 4146 PetscFunctionBegin; 4147 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4148 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4149 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4150 PetscCall(PetscMalloc1(size, &mesh->cones)); 4151 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4152 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4153 if (maxSupportSize) { 4154 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4155 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4156 PetscCall(PetscMalloc1(size, &mesh->supports)); 4157 } 4158 PetscFunctionReturn(PETSC_SUCCESS); 4159 } 4160 4161 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4162 { 4163 PetscFunctionBegin; 4164 if (subdm) PetscCall(DMClone(dm, subdm)); 4165 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4166 if (subdm) (*subdm)->useNatural = dm->useNatural; 4167 if (dm->useNatural && dm->sfMigration) { 4168 PetscSF sfNatural; 4169 4170 (*subdm)->sfMigration = dm->sfMigration; 4171 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4172 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4173 (*subdm)->sfNatural = sfNatural; 4174 } 4175 PetscFunctionReturn(PETSC_SUCCESS); 4176 } 4177 4178 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4179 { 4180 PetscInt i = 0; 4181 4182 PetscFunctionBegin; 4183 PetscCall(DMClone(dms[0], superdm)); 4184 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4185 (*superdm)->useNatural = PETSC_FALSE; 4186 for (i = 0; i < len; i++) { 4187 if (dms[i]->useNatural && dms[i]->sfMigration) { 4188 PetscSF sfNatural; 4189 4190 (*superdm)->sfMigration = dms[i]->sfMigration; 4191 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4192 (*superdm)->useNatural = PETSC_TRUE; 4193 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4194 (*superdm)->sfNatural = sfNatural; 4195 break; 4196 } 4197 } 4198 PetscFunctionReturn(PETSC_SUCCESS); 4199 } 4200 4201 /*@ 4202 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4203 4204 Not Collective 4205 4206 Input Parameter: 4207 . dm - The `DMPLEX` 4208 4209 Level: beginner 4210 4211 Note: 4212 This should be called after all calls to `DMPlexSetCone()` 4213 4214 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4215 @*/ 4216 PetscErrorCode DMPlexSymmetrize(DM dm) 4217 { 4218 DM_Plex *mesh = (DM_Plex *)dm->data; 4219 PetscInt *offsets; 4220 PetscInt supportSize; 4221 PetscInt pStart, pEnd, p; 4222 4223 PetscFunctionBegin; 4224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4225 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4226 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4227 /* Calculate support sizes */ 4228 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4229 for (p = pStart; p < pEnd; ++p) { 4230 PetscInt dof, off, c; 4231 4232 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4233 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4234 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4235 } 4236 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4237 /* Calculate supports */ 4238 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4239 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4240 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4241 for (p = pStart; p < pEnd; ++p) { 4242 PetscInt dof, off, c; 4243 4244 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4245 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4246 for (c = off; c < off + dof; ++c) { 4247 const PetscInt q = mesh->cones[c]; 4248 PetscInt offS; 4249 4250 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4251 4252 mesh->supports[offS + offsets[q]] = p; 4253 ++offsets[q]; 4254 } 4255 } 4256 PetscCall(PetscFree(offsets)); 4257 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4258 PetscFunctionReturn(PETSC_SUCCESS); 4259 } 4260 4261 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4262 { 4263 IS stratumIS; 4264 4265 PetscFunctionBegin; 4266 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4267 if (PetscDefined(USE_DEBUG)) { 4268 PetscInt qStart, qEnd, numLevels, level; 4269 PetscBool overlap = PETSC_FALSE; 4270 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4271 for (level = 0; level < numLevels; level++) { 4272 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4273 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4274 overlap = PETSC_TRUE; 4275 break; 4276 } 4277 } 4278 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); 4279 } 4280 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4281 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4282 PetscCall(ISDestroy(&stratumIS)); 4283 PetscFunctionReturn(PETSC_SUCCESS); 4284 } 4285 4286 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4287 { 4288 PetscInt *pMin, *pMax; 4289 PetscInt pStart, pEnd; 4290 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4291 4292 PetscFunctionBegin; 4293 { 4294 DMLabel label2; 4295 4296 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4297 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4298 } 4299 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4300 for (PetscInt p = pStart; p < pEnd; ++p) { 4301 DMPolytopeType ct; 4302 4303 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4304 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4305 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4306 } 4307 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4308 for (PetscInt d = dmin; d <= dmax; ++d) { 4309 pMin[d] = PETSC_MAX_INT; 4310 pMax[d] = PETSC_MIN_INT; 4311 } 4312 for (PetscInt p = pStart; p < pEnd; ++p) { 4313 DMPolytopeType ct; 4314 PetscInt d; 4315 4316 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4317 d = DMPolytopeTypeGetDim(ct); 4318 pMin[d] = PetscMin(p, pMin[d]); 4319 pMax[d] = PetscMax(p, pMax[d]); 4320 } 4321 for (PetscInt d = dmin; d <= dmax; ++d) { 4322 if (pMin[d] > pMax[d]) continue; 4323 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4324 } 4325 PetscCall(PetscFree2(pMin, pMax)); 4326 PetscFunctionReturn(PETSC_SUCCESS); 4327 } 4328 4329 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4330 { 4331 PetscInt pStart, pEnd; 4332 PetscInt numRoots = 0, numLeaves = 0; 4333 4334 PetscFunctionBegin; 4335 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4336 { 4337 /* Initialize roots and count leaves */ 4338 PetscInt sMin = PETSC_MAX_INT; 4339 PetscInt sMax = PETSC_MIN_INT; 4340 PetscInt coneSize, supportSize; 4341 4342 for (PetscInt p = pStart; p < pEnd; ++p) { 4343 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4344 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4345 if (!coneSize && supportSize) { 4346 sMin = PetscMin(p, sMin); 4347 sMax = PetscMax(p, sMax); 4348 ++numRoots; 4349 } else if (!supportSize && coneSize) { 4350 ++numLeaves; 4351 } else if (!supportSize && !coneSize) { 4352 /* Isolated points */ 4353 sMin = PetscMin(p, sMin); 4354 sMax = PetscMax(p, sMax); 4355 } 4356 } 4357 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4358 } 4359 4360 if (numRoots + numLeaves == (pEnd - pStart)) { 4361 PetscInt sMin = PETSC_MAX_INT; 4362 PetscInt sMax = PETSC_MIN_INT; 4363 PetscInt coneSize, supportSize; 4364 4365 for (PetscInt p = pStart; p < pEnd; ++p) { 4366 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4367 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4368 if (!supportSize && coneSize) { 4369 sMin = PetscMin(p, sMin); 4370 sMax = PetscMax(p, sMax); 4371 } 4372 } 4373 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4374 } else { 4375 PetscInt level = 0; 4376 PetscInt qStart, qEnd; 4377 4378 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4379 while (qEnd > qStart) { 4380 PetscInt sMin = PETSC_MAX_INT; 4381 PetscInt sMax = PETSC_MIN_INT; 4382 4383 for (PetscInt q = qStart; q < qEnd; ++q) { 4384 const PetscInt *support; 4385 PetscInt supportSize; 4386 4387 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4388 PetscCall(DMPlexGetSupport(dm, q, &support)); 4389 for (PetscInt s = 0; s < supportSize; ++s) { 4390 sMin = PetscMin(support[s], sMin); 4391 sMax = PetscMax(support[s], sMax); 4392 } 4393 } 4394 PetscCall(DMLabelGetNumValues(label, &level)); 4395 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4396 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4397 } 4398 } 4399 PetscFunctionReturn(PETSC_SUCCESS); 4400 } 4401 4402 /*@ 4403 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4404 4405 Collective 4406 4407 Input Parameter: 4408 . dm - The `DMPLEX` 4409 4410 Level: beginner 4411 4412 Notes: 4413 The strata group all points of the same grade, and this function calculates the strata. This 4414 grade can be seen as the height (or depth) of the point in the DAG. 4415 4416 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4417 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4418 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4419 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4420 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4421 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4422 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4423 4424 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4425 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4426 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 4427 to interpolate only that one (e0), so that 4428 .vb 4429 cone(c0) = {e0, v2} 4430 cone(e0) = {v0, v1} 4431 .ve 4432 If `DMPlexStratify()` is run on this mesh, it will give depths 4433 .vb 4434 depth 0 = {v0, v1, v2} 4435 depth 1 = {e0, c0} 4436 .ve 4437 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4438 4439 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4440 4441 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4442 @*/ 4443 PetscErrorCode DMPlexStratify(DM dm) 4444 { 4445 DM_Plex *mesh = (DM_Plex *)dm->data; 4446 DMLabel label; 4447 PetscBool flg = PETSC_FALSE; 4448 4449 PetscFunctionBegin; 4450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4451 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4452 4453 // Create depth label 4454 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4455 PetscCall(DMCreateLabel(dm, "depth")); 4456 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4457 4458 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4459 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4460 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4461 4462 { /* just in case there is an empty process */ 4463 PetscInt numValues, maxValues = 0, v; 4464 4465 PetscCall(DMLabelGetNumValues(label, &numValues)); 4466 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4467 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4468 } 4469 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4470 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4471 PetscFunctionReturn(PETSC_SUCCESS); 4472 } 4473 4474 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4475 { 4476 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4477 PetscInt dim, depth, pheight, coneSize; 4478 4479 PetscFunctionBeginHot; 4480 PetscCall(DMGetDimension(dm, &dim)); 4481 PetscCall(DMPlexGetDepth(dm, &depth)); 4482 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4483 pheight = depth - pdepth; 4484 if (depth <= 1) { 4485 switch (pdepth) { 4486 case 0: 4487 ct = DM_POLYTOPE_POINT; 4488 break; 4489 case 1: 4490 switch (coneSize) { 4491 case 2: 4492 ct = DM_POLYTOPE_SEGMENT; 4493 break; 4494 case 3: 4495 ct = DM_POLYTOPE_TRIANGLE; 4496 break; 4497 case 4: 4498 switch (dim) { 4499 case 2: 4500 ct = DM_POLYTOPE_QUADRILATERAL; 4501 break; 4502 case 3: 4503 ct = DM_POLYTOPE_TETRAHEDRON; 4504 break; 4505 default: 4506 break; 4507 } 4508 break; 4509 case 5: 4510 ct = DM_POLYTOPE_PYRAMID; 4511 break; 4512 case 6: 4513 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4514 break; 4515 case 8: 4516 ct = DM_POLYTOPE_HEXAHEDRON; 4517 break; 4518 default: 4519 break; 4520 } 4521 } 4522 } else { 4523 if (pdepth == 0) { 4524 ct = DM_POLYTOPE_POINT; 4525 } else if (pheight == 0) { 4526 switch (dim) { 4527 case 1: 4528 switch (coneSize) { 4529 case 2: 4530 ct = DM_POLYTOPE_SEGMENT; 4531 break; 4532 default: 4533 break; 4534 } 4535 break; 4536 case 2: 4537 switch (coneSize) { 4538 case 3: 4539 ct = DM_POLYTOPE_TRIANGLE; 4540 break; 4541 case 4: 4542 ct = DM_POLYTOPE_QUADRILATERAL; 4543 break; 4544 default: 4545 break; 4546 } 4547 break; 4548 case 3: 4549 switch (coneSize) { 4550 case 4: 4551 ct = DM_POLYTOPE_TETRAHEDRON; 4552 break; 4553 case 5: { 4554 const PetscInt *cone; 4555 PetscInt faceConeSize; 4556 4557 PetscCall(DMPlexGetCone(dm, p, &cone)); 4558 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4559 switch (faceConeSize) { 4560 case 3: 4561 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4562 break; 4563 case 4: 4564 ct = DM_POLYTOPE_PYRAMID; 4565 break; 4566 } 4567 } break; 4568 case 6: 4569 ct = DM_POLYTOPE_HEXAHEDRON; 4570 break; 4571 default: 4572 break; 4573 } 4574 break; 4575 default: 4576 break; 4577 } 4578 } else if (pheight > 0) { 4579 switch (coneSize) { 4580 case 2: 4581 ct = DM_POLYTOPE_SEGMENT; 4582 break; 4583 case 3: 4584 ct = DM_POLYTOPE_TRIANGLE; 4585 break; 4586 case 4: 4587 ct = DM_POLYTOPE_QUADRILATERAL; 4588 break; 4589 default: 4590 break; 4591 } 4592 } 4593 } 4594 *pt = ct; 4595 PetscFunctionReturn(PETSC_SUCCESS); 4596 } 4597 4598 /*@ 4599 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4600 4601 Collective 4602 4603 Input Parameter: 4604 . dm - The `DMPLEX` 4605 4606 Level: developer 4607 4608 Note: 4609 This function is normally called automatically when a cell type is requested. It creates an 4610 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4611 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4612 4613 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4614 4615 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4616 @*/ 4617 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4618 { 4619 DM_Plex *mesh; 4620 DMLabel ctLabel; 4621 PetscInt pStart, pEnd, p; 4622 4623 PetscFunctionBegin; 4624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4625 mesh = (DM_Plex *)dm->data; 4626 PetscCall(DMCreateLabel(dm, "celltype")); 4627 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4628 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4629 PetscCall(PetscFree(mesh->cellTypes)); 4630 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4631 for (p = pStart; p < pEnd; ++p) { 4632 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4633 PetscInt pdepth; 4634 4635 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4636 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4637 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4638 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4639 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4640 } 4641 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4642 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4643 PetscFunctionReturn(PETSC_SUCCESS); 4644 } 4645 4646 /*@C 4647 DMPlexGetJoin - Get an array for the join of the set of points 4648 4649 Not Collective 4650 4651 Input Parameters: 4652 + dm - The `DMPLEX` object 4653 . numPoints - The number of input points for the join 4654 - points - The input points 4655 4656 Output Parameters: 4657 + numCoveredPoints - The number of points in the join 4658 - coveredPoints - The points in the join 4659 4660 Level: intermediate 4661 4662 Note: 4663 Currently, this is restricted to a single level join 4664 4665 Fortran Notes: 4666 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4667 4668 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4669 @*/ 4670 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4671 { 4672 DM_Plex *mesh = (DM_Plex *)dm->data; 4673 PetscInt *join[2]; 4674 PetscInt joinSize, i = 0; 4675 PetscInt dof, off, p, c, m; 4676 PetscInt maxSupportSize; 4677 4678 PetscFunctionBegin; 4679 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4680 PetscAssertPointer(points, 3); 4681 PetscAssertPointer(numCoveredPoints, 4); 4682 PetscAssertPointer(coveredPoints, 5); 4683 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4684 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4685 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4686 /* Copy in support of first point */ 4687 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4688 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4689 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4690 /* Check each successive support */ 4691 for (p = 1; p < numPoints; ++p) { 4692 PetscInt newJoinSize = 0; 4693 4694 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4695 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4696 for (c = 0; c < dof; ++c) { 4697 const PetscInt point = mesh->supports[off + c]; 4698 4699 for (m = 0; m < joinSize; ++m) { 4700 if (point == join[i][m]) { 4701 join[1 - i][newJoinSize++] = point; 4702 break; 4703 } 4704 } 4705 } 4706 joinSize = newJoinSize; 4707 i = 1 - i; 4708 } 4709 *numCoveredPoints = joinSize; 4710 *coveredPoints = join[i]; 4711 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4712 PetscFunctionReturn(PETSC_SUCCESS); 4713 } 4714 4715 /*@C 4716 DMPlexRestoreJoin - Restore an array for the join of the set of points 4717 4718 Not Collective 4719 4720 Input Parameters: 4721 + dm - The `DMPLEX` object 4722 . numPoints - The number of input points for the join 4723 - points - The input points 4724 4725 Output Parameters: 4726 + numCoveredPoints - The number of points in the join 4727 - coveredPoints - The points in the join 4728 4729 Level: intermediate 4730 4731 Fortran Notes: 4732 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4733 4734 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4735 @*/ 4736 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4737 { 4738 PetscFunctionBegin; 4739 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4740 if (points) PetscAssertPointer(points, 3); 4741 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4742 PetscAssertPointer(coveredPoints, 5); 4743 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4744 if (numCoveredPoints) *numCoveredPoints = 0; 4745 PetscFunctionReturn(PETSC_SUCCESS); 4746 } 4747 4748 /*@C 4749 DMPlexGetFullJoin - Get an array for the join of the set of points 4750 4751 Not Collective 4752 4753 Input Parameters: 4754 + dm - The `DMPLEX` object 4755 . numPoints - The number of input points for the join 4756 - points - The input points 4757 4758 Output Parameters: 4759 + numCoveredPoints - The number of points in the join 4760 - coveredPoints - The points in the join 4761 4762 Level: intermediate 4763 4764 Fortran Notes: 4765 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4766 4767 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4768 @*/ 4769 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4770 { 4771 PetscInt *offsets, **closures; 4772 PetscInt *join[2]; 4773 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4774 PetscInt p, d, c, m, ms; 4775 4776 PetscFunctionBegin; 4777 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4778 PetscAssertPointer(points, 3); 4779 PetscAssertPointer(numCoveredPoints, 4); 4780 PetscAssertPointer(coveredPoints, 5); 4781 4782 PetscCall(DMPlexGetDepth(dm, &depth)); 4783 PetscCall(PetscCalloc1(numPoints, &closures)); 4784 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4785 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4786 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4787 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4788 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4789 4790 for (p = 0; p < numPoints; ++p) { 4791 PetscInt closureSize; 4792 4793 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4794 4795 offsets[p * (depth + 2) + 0] = 0; 4796 for (d = 0; d < depth + 1; ++d) { 4797 PetscInt pStart, pEnd, i; 4798 4799 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4800 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4801 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4802 offsets[p * (depth + 2) + d + 1] = i; 4803 break; 4804 } 4805 } 4806 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4807 } 4808 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); 4809 } 4810 for (d = 0; d < depth + 1; ++d) { 4811 PetscInt dof; 4812 4813 /* Copy in support of first point */ 4814 dof = offsets[d + 1] - offsets[d]; 4815 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4816 /* Check each successive cone */ 4817 for (p = 1; p < numPoints && joinSize; ++p) { 4818 PetscInt newJoinSize = 0; 4819 4820 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4821 for (c = 0; c < dof; ++c) { 4822 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4823 4824 for (m = 0; m < joinSize; ++m) { 4825 if (point == join[i][m]) { 4826 join[1 - i][newJoinSize++] = point; 4827 break; 4828 } 4829 } 4830 } 4831 joinSize = newJoinSize; 4832 i = 1 - i; 4833 } 4834 if (joinSize) break; 4835 } 4836 *numCoveredPoints = joinSize; 4837 *coveredPoints = join[i]; 4838 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4839 PetscCall(PetscFree(closures)); 4840 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4841 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4842 PetscFunctionReturn(PETSC_SUCCESS); 4843 } 4844 4845 /*@C 4846 DMPlexGetMeet - Get an array for the meet of the set of points 4847 4848 Not Collective 4849 4850 Input Parameters: 4851 + dm - The `DMPLEX` object 4852 . numPoints - The number of input points for the meet 4853 - points - The input points 4854 4855 Output Parameters: 4856 + numCoveringPoints - The number of points in the meet 4857 - coveringPoints - The points in the meet 4858 4859 Level: intermediate 4860 4861 Note: 4862 Currently, this is restricted to a single level meet 4863 4864 Fortran Notes: 4865 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4866 4867 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4868 @*/ 4869 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4870 { 4871 DM_Plex *mesh = (DM_Plex *)dm->data; 4872 PetscInt *meet[2]; 4873 PetscInt meetSize, i = 0; 4874 PetscInt dof, off, p, c, m; 4875 PetscInt maxConeSize; 4876 4877 PetscFunctionBegin; 4878 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4879 PetscAssertPointer(points, 3); 4880 PetscAssertPointer(numCoveringPoints, 4); 4881 PetscAssertPointer(coveringPoints, 5); 4882 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4883 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4884 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4885 /* Copy in cone of first point */ 4886 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4887 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4888 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4889 /* Check each successive cone */ 4890 for (p = 1; p < numPoints; ++p) { 4891 PetscInt newMeetSize = 0; 4892 4893 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4894 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4895 for (c = 0; c < dof; ++c) { 4896 const PetscInt point = mesh->cones[off + c]; 4897 4898 for (m = 0; m < meetSize; ++m) { 4899 if (point == meet[i][m]) { 4900 meet[1 - i][newMeetSize++] = point; 4901 break; 4902 } 4903 } 4904 } 4905 meetSize = newMeetSize; 4906 i = 1 - i; 4907 } 4908 *numCoveringPoints = meetSize; 4909 *coveringPoints = meet[i]; 4910 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4911 PetscFunctionReturn(PETSC_SUCCESS); 4912 } 4913 4914 /*@C 4915 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4916 4917 Not Collective 4918 4919 Input Parameters: 4920 + dm - The `DMPLEX` object 4921 . numPoints - The number of input points for the meet 4922 - points - The input points 4923 4924 Output Parameters: 4925 + numCoveredPoints - The number of points in the meet 4926 - coveredPoints - The points in the meet 4927 4928 Level: intermediate 4929 4930 Fortran Notes: 4931 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4932 4933 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4934 @*/ 4935 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4936 { 4937 PetscFunctionBegin; 4938 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4939 if (points) PetscAssertPointer(points, 3); 4940 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4941 PetscAssertPointer(coveredPoints, 5); 4942 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4943 if (numCoveredPoints) *numCoveredPoints = 0; 4944 PetscFunctionReturn(PETSC_SUCCESS); 4945 } 4946 4947 /*@C 4948 DMPlexGetFullMeet - Get an array for the meet of the set of points 4949 4950 Not Collective 4951 4952 Input Parameters: 4953 + dm - The `DMPLEX` object 4954 . numPoints - The number of input points for the meet 4955 - points - The input points 4956 4957 Output Parameters: 4958 + numCoveredPoints - The number of points in the meet 4959 - coveredPoints - The points in the meet 4960 4961 Level: intermediate 4962 4963 Fortran Notes: 4964 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4965 4966 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4967 @*/ 4968 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4969 { 4970 PetscInt *offsets, **closures; 4971 PetscInt *meet[2]; 4972 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4973 PetscInt p, h, c, m, mc; 4974 4975 PetscFunctionBegin; 4976 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4977 PetscAssertPointer(points, 3); 4978 PetscAssertPointer(numCoveredPoints, 4); 4979 PetscAssertPointer(coveredPoints, 5); 4980 4981 PetscCall(DMPlexGetDepth(dm, &height)); 4982 PetscCall(PetscMalloc1(numPoints, &closures)); 4983 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4984 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4985 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4986 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4987 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4988 4989 for (p = 0; p < numPoints; ++p) { 4990 PetscInt closureSize; 4991 4992 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4993 4994 offsets[p * (height + 2) + 0] = 0; 4995 for (h = 0; h < height + 1; ++h) { 4996 PetscInt pStart, pEnd, i; 4997 4998 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4999 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5000 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5001 offsets[p * (height + 2) + h + 1] = i; 5002 break; 5003 } 5004 } 5005 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5006 } 5007 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); 5008 } 5009 for (h = 0; h < height + 1; ++h) { 5010 PetscInt dof; 5011 5012 /* Copy in cone of first point */ 5013 dof = offsets[h + 1] - offsets[h]; 5014 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5015 /* Check each successive cone */ 5016 for (p = 1; p < numPoints && meetSize; ++p) { 5017 PetscInt newMeetSize = 0; 5018 5019 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5020 for (c = 0; c < dof; ++c) { 5021 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5022 5023 for (m = 0; m < meetSize; ++m) { 5024 if (point == meet[i][m]) { 5025 meet[1 - i][newMeetSize++] = point; 5026 break; 5027 } 5028 } 5029 } 5030 meetSize = newMeetSize; 5031 i = 1 - i; 5032 } 5033 if (meetSize) break; 5034 } 5035 *numCoveredPoints = meetSize; 5036 *coveredPoints = meet[i]; 5037 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5038 PetscCall(PetscFree(closures)); 5039 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5040 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5041 PetscFunctionReturn(PETSC_SUCCESS); 5042 } 5043 5044 /*@C 5045 DMPlexEqual - Determine if two `DM` have the same topology 5046 5047 Not Collective 5048 5049 Input Parameters: 5050 + dmA - A `DMPLEX` object 5051 - dmB - A `DMPLEX` object 5052 5053 Output Parameter: 5054 . equal - `PETSC_TRUE` if the topologies are identical 5055 5056 Level: intermediate 5057 5058 Note: 5059 We are not solving graph isomorphism, so we do not permute. 5060 5061 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5062 @*/ 5063 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5064 { 5065 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5066 5067 PetscFunctionBegin; 5068 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5069 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5070 PetscAssertPointer(equal, 3); 5071 5072 *equal = PETSC_FALSE; 5073 PetscCall(DMPlexGetDepth(dmA, &depth)); 5074 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5075 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5076 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5077 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5078 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5079 for (p = pStart; p < pEnd; ++p) { 5080 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5081 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5082 5083 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5084 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5085 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5086 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5087 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5088 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5089 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5090 for (c = 0; c < coneSize; ++c) { 5091 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5092 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5093 } 5094 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5095 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5096 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5097 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5098 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5099 for (s = 0; s < supportSize; ++s) { 5100 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5101 } 5102 } 5103 *equal = PETSC_TRUE; 5104 PetscFunctionReturn(PETSC_SUCCESS); 5105 } 5106 5107 /*@C 5108 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5109 5110 Not Collective 5111 5112 Input Parameters: 5113 + dm - The `DMPLEX` 5114 . cellDim - The cell dimension 5115 - numCorners - The number of vertices on a cell 5116 5117 Output Parameter: 5118 . numFaceVertices - The number of vertices on a face 5119 5120 Level: developer 5121 5122 Note: 5123 Of course this can only work for a restricted set of symmetric shapes 5124 5125 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5126 @*/ 5127 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5128 { 5129 MPI_Comm comm; 5130 5131 PetscFunctionBegin; 5132 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5133 PetscAssertPointer(numFaceVertices, 4); 5134 switch (cellDim) { 5135 case 0: 5136 *numFaceVertices = 0; 5137 break; 5138 case 1: 5139 *numFaceVertices = 1; 5140 break; 5141 case 2: 5142 switch (numCorners) { 5143 case 3: /* triangle */ 5144 *numFaceVertices = 2; /* Edge has 2 vertices */ 5145 break; 5146 case 4: /* quadrilateral */ 5147 *numFaceVertices = 2; /* Edge has 2 vertices */ 5148 break; 5149 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5150 *numFaceVertices = 3; /* Edge has 3 vertices */ 5151 break; 5152 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5153 *numFaceVertices = 3; /* Edge has 3 vertices */ 5154 break; 5155 default: 5156 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5157 } 5158 break; 5159 case 3: 5160 switch (numCorners) { 5161 case 4: /* tetradehdron */ 5162 *numFaceVertices = 3; /* Face has 3 vertices */ 5163 break; 5164 case 6: /* tet cohesive cells */ 5165 *numFaceVertices = 4; /* Face has 4 vertices */ 5166 break; 5167 case 8: /* hexahedron */ 5168 *numFaceVertices = 4; /* Face has 4 vertices */ 5169 break; 5170 case 9: /* tet cohesive Lagrange cells */ 5171 *numFaceVertices = 6; /* Face has 6 vertices */ 5172 break; 5173 case 10: /* quadratic tetrahedron */ 5174 *numFaceVertices = 6; /* Face has 6 vertices */ 5175 break; 5176 case 12: /* hex cohesive Lagrange cells */ 5177 *numFaceVertices = 6; /* Face has 6 vertices */ 5178 break; 5179 case 18: /* quadratic tet cohesive Lagrange cells */ 5180 *numFaceVertices = 6; /* Face has 6 vertices */ 5181 break; 5182 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5183 *numFaceVertices = 9; /* Face has 9 vertices */ 5184 break; 5185 default: 5186 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5187 } 5188 break; 5189 default: 5190 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5191 } 5192 PetscFunctionReturn(PETSC_SUCCESS); 5193 } 5194 5195 /*@ 5196 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5197 5198 Not Collective 5199 5200 Input Parameter: 5201 . dm - The `DMPLEX` object 5202 5203 Output Parameter: 5204 . depthLabel - The `DMLabel` recording point depth 5205 5206 Level: developer 5207 5208 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5209 @*/ 5210 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5211 { 5212 PetscFunctionBegin; 5213 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5214 PetscAssertPointer(depthLabel, 2); 5215 *depthLabel = dm->depthLabel; 5216 PetscFunctionReturn(PETSC_SUCCESS); 5217 } 5218 5219 /*@ 5220 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5221 5222 Not Collective 5223 5224 Input Parameter: 5225 . dm - The `DMPLEX` object 5226 5227 Output Parameter: 5228 . depth - The number of strata (breadth first levels) in the DAG 5229 5230 Level: developer 5231 5232 Notes: 5233 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5234 5235 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5236 5237 An empty mesh gives -1. 5238 5239 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5240 @*/ 5241 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5242 { 5243 DM_Plex *mesh = (DM_Plex *)dm->data; 5244 DMLabel label; 5245 PetscInt d = -1; 5246 5247 PetscFunctionBegin; 5248 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5249 PetscAssertPointer(depth, 2); 5250 if (mesh->tr) { 5251 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5252 } else { 5253 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5254 // Allow missing depths 5255 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5256 *depth = d; 5257 } 5258 PetscFunctionReturn(PETSC_SUCCESS); 5259 } 5260 5261 /*@ 5262 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5263 5264 Not Collective 5265 5266 Input Parameters: 5267 + dm - The `DMPLEX` object 5268 - depth - The requested depth 5269 5270 Output Parameters: 5271 + start - The first point at this `depth` 5272 - end - One beyond the last point at this `depth` 5273 5274 Level: developer 5275 5276 Notes: 5277 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5278 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5279 higher dimension, e.g., "edges". 5280 5281 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5282 @*/ 5283 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5284 { 5285 DM_Plex *mesh = (DM_Plex *)dm->data; 5286 DMLabel label; 5287 PetscInt pStart, pEnd; 5288 5289 PetscFunctionBegin; 5290 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5291 if (start) { 5292 PetscAssertPointer(start, 3); 5293 *start = 0; 5294 } 5295 if (end) { 5296 PetscAssertPointer(end, 4); 5297 *end = 0; 5298 } 5299 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5300 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5301 if (depth < 0) { 5302 if (start) *start = pStart; 5303 if (end) *end = pEnd; 5304 PetscFunctionReturn(PETSC_SUCCESS); 5305 } 5306 if (mesh->tr) { 5307 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5308 } else { 5309 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5310 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5311 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5312 } 5313 PetscFunctionReturn(PETSC_SUCCESS); 5314 } 5315 5316 /*@ 5317 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5318 5319 Not Collective 5320 5321 Input Parameters: 5322 + dm - The `DMPLEX` object 5323 - height - The requested height 5324 5325 Output Parameters: 5326 + start - The first point at this `height` 5327 - end - One beyond the last point at this `height` 5328 5329 Level: developer 5330 5331 Notes: 5332 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5333 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5334 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5335 5336 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5337 @*/ 5338 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5339 { 5340 DMLabel label; 5341 PetscInt depth, pStart, pEnd; 5342 5343 PetscFunctionBegin; 5344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5345 if (start) { 5346 PetscAssertPointer(start, 3); 5347 *start = 0; 5348 } 5349 if (end) { 5350 PetscAssertPointer(end, 4); 5351 *end = 0; 5352 } 5353 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5354 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5355 if (height < 0) { 5356 if (start) *start = pStart; 5357 if (end) *end = pEnd; 5358 PetscFunctionReturn(PETSC_SUCCESS); 5359 } 5360 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5361 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5362 else PetscCall(DMGetDimension(dm, &depth)); 5363 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5364 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5365 PetscFunctionReturn(PETSC_SUCCESS); 5366 } 5367 5368 /*@ 5369 DMPlexGetPointDepth - Get the `depth` of a given point 5370 5371 Not Collective 5372 5373 Input Parameters: 5374 + dm - The `DMPLEX` object 5375 - point - The point 5376 5377 Output Parameter: 5378 . depth - The depth of the `point` 5379 5380 Level: intermediate 5381 5382 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5383 @*/ 5384 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5385 { 5386 PetscFunctionBegin; 5387 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5388 PetscAssertPointer(depth, 3); 5389 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5390 PetscFunctionReturn(PETSC_SUCCESS); 5391 } 5392 5393 /*@ 5394 DMPlexGetPointHeight - Get the `height` of a given point 5395 5396 Not Collective 5397 5398 Input Parameters: 5399 + dm - The `DMPLEX` object 5400 - point - The point 5401 5402 Output Parameter: 5403 . height - The height of the `point` 5404 5405 Level: intermediate 5406 5407 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5408 @*/ 5409 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5410 { 5411 PetscInt n, pDepth; 5412 5413 PetscFunctionBegin; 5414 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5415 PetscAssertPointer(height, 3); 5416 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5417 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5418 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5419 PetscFunctionReturn(PETSC_SUCCESS); 5420 } 5421 5422 /*@ 5423 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5424 5425 Not Collective 5426 5427 Input Parameter: 5428 . dm - The `DMPLEX` object 5429 5430 Output Parameter: 5431 . celltypeLabel - The `DMLabel` recording cell polytope type 5432 5433 Level: developer 5434 5435 Note: 5436 This function will trigger automatica computation of cell types. This can be disabled by calling 5437 `DMCreateLabel`(dm, "celltype") beforehand. 5438 5439 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5440 @*/ 5441 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5442 { 5443 PetscFunctionBegin; 5444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5445 PetscAssertPointer(celltypeLabel, 2); 5446 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5447 *celltypeLabel = dm->celltypeLabel; 5448 PetscFunctionReturn(PETSC_SUCCESS); 5449 } 5450 5451 /*@ 5452 DMPlexGetCellType - Get the polytope type of a given cell 5453 5454 Not Collective 5455 5456 Input Parameters: 5457 + dm - The `DMPLEX` object 5458 - cell - The cell 5459 5460 Output Parameter: 5461 . celltype - The polytope type of the cell 5462 5463 Level: intermediate 5464 5465 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5466 @*/ 5467 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5468 { 5469 DM_Plex *mesh = (DM_Plex *)dm->data; 5470 DMLabel label; 5471 PetscInt ct; 5472 5473 PetscFunctionBegin; 5474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5475 PetscAssertPointer(celltype, 3); 5476 if (mesh->tr) { 5477 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5478 } else { 5479 PetscInt pStart, pEnd; 5480 5481 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5482 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5483 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5484 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5485 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5486 for (PetscInt p = pStart; p < pEnd; p++) { 5487 PetscCall(DMLabelGetValue(label, p, &ct)); 5488 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5489 } 5490 } 5491 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5492 if (PetscDefined(USE_DEBUG)) { 5493 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5494 PetscCall(DMLabelGetValue(label, cell, &ct)); 5495 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5496 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5497 } 5498 } 5499 PetscFunctionReturn(PETSC_SUCCESS); 5500 } 5501 5502 /*@ 5503 DMPlexSetCellType - Set the polytope type of a given cell 5504 5505 Not Collective 5506 5507 Input Parameters: 5508 + dm - The `DMPLEX` object 5509 . cell - The cell 5510 - celltype - The polytope type of the cell 5511 5512 Level: advanced 5513 5514 Note: 5515 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5516 is executed. This function will override the computed type. However, if automatic classification will not succeed 5517 and a user wants to manually specify all types, the classification must be disabled by calling 5518 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5519 5520 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5521 @*/ 5522 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5523 { 5524 DM_Plex *mesh = (DM_Plex *)dm->data; 5525 DMLabel label; 5526 PetscInt pStart, pEnd; 5527 5528 PetscFunctionBegin; 5529 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5530 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5531 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5532 PetscCall(DMLabelSetValue(label, cell, celltype)); 5533 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5534 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5535 PetscFunctionReturn(PETSC_SUCCESS); 5536 } 5537 5538 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5539 { 5540 PetscSection section; 5541 PetscInt maxHeight; 5542 const char *prefix; 5543 5544 PetscFunctionBegin; 5545 PetscCall(DMClone(dm, cdm)); 5546 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5547 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5548 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5549 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5550 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5551 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5552 PetscCall(DMSetLocalSection(*cdm, section)); 5553 PetscCall(PetscSectionDestroy(§ion)); 5554 5555 PetscCall(DMSetNumFields(*cdm, 1)); 5556 PetscCall(DMCreateDS(*cdm)); 5557 (*cdm)->cloneOpts = PETSC_TRUE; 5558 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5559 PetscFunctionReturn(PETSC_SUCCESS); 5560 } 5561 5562 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5563 { 5564 Vec coordsLocal, cellCoordsLocal; 5565 DM coordsDM, cellCoordsDM; 5566 5567 PetscFunctionBegin; 5568 *field = NULL; 5569 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5570 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5571 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5572 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5573 if (coordsLocal && coordsDM) { 5574 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5575 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5576 } 5577 PetscFunctionReturn(PETSC_SUCCESS); 5578 } 5579 5580 /*@C 5581 DMPlexGetConeSection - Return a section which describes the layout of cone data 5582 5583 Not Collective 5584 5585 Input Parameter: 5586 . dm - The `DMPLEX` object 5587 5588 Output Parameter: 5589 . section - The `PetscSection` object 5590 5591 Level: developer 5592 5593 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5594 @*/ 5595 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5596 { 5597 DM_Plex *mesh = (DM_Plex *)dm->data; 5598 5599 PetscFunctionBegin; 5600 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5601 if (section) *section = mesh->coneSection; 5602 PetscFunctionReturn(PETSC_SUCCESS); 5603 } 5604 5605 /*@C 5606 DMPlexGetSupportSection - Return a section which describes the layout of support data 5607 5608 Not Collective 5609 5610 Input Parameter: 5611 . dm - The `DMPLEX` object 5612 5613 Output Parameter: 5614 . section - The `PetscSection` object 5615 5616 Level: developer 5617 5618 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5619 @*/ 5620 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5621 { 5622 DM_Plex *mesh = (DM_Plex *)dm->data; 5623 5624 PetscFunctionBegin; 5625 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5626 if (section) *section = mesh->supportSection; 5627 PetscFunctionReturn(PETSC_SUCCESS); 5628 } 5629 5630 /*@C 5631 DMPlexGetCones - Return cone data 5632 5633 Not Collective 5634 5635 Input Parameter: 5636 . dm - The `DMPLEX` object 5637 5638 Output Parameter: 5639 . cones - The cone for each point 5640 5641 Level: developer 5642 5643 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5644 @*/ 5645 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5646 { 5647 DM_Plex *mesh = (DM_Plex *)dm->data; 5648 5649 PetscFunctionBegin; 5650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5651 if (cones) *cones = mesh->cones; 5652 PetscFunctionReturn(PETSC_SUCCESS); 5653 } 5654 5655 /*@C 5656 DMPlexGetConeOrientations - Return cone orientation data 5657 5658 Not Collective 5659 5660 Input Parameter: 5661 . dm - The `DMPLEX` object 5662 5663 Output Parameter: 5664 . coneOrientations - The array of cone orientations for all points 5665 5666 Level: developer 5667 5668 Notes: 5669 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5670 5671 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5672 5673 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5674 @*/ 5675 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5676 { 5677 DM_Plex *mesh = (DM_Plex *)dm->data; 5678 5679 PetscFunctionBegin; 5680 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5681 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5682 PetscFunctionReturn(PETSC_SUCCESS); 5683 } 5684 5685 /******************************** FEM Support **********************************/ 5686 5687 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5688 { 5689 PetscInt depth; 5690 5691 PetscFunctionBegin; 5692 PetscCall(DMPlexGetDepth(plex, &depth)); 5693 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5694 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5695 PetscFunctionReturn(PETSC_SUCCESS); 5696 } 5697 5698 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5699 { 5700 PetscInt depth; 5701 5702 PetscFunctionBegin; 5703 PetscCall(DMPlexGetDepth(plex, &depth)); 5704 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5705 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5706 PetscFunctionReturn(PETSC_SUCCESS); 5707 } 5708 5709 /* 5710 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5711 representing a line in the section. 5712 */ 5713 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5714 { 5715 PetscObject obj; 5716 PetscClassId id; 5717 PetscFE fe = NULL; 5718 5719 PetscFunctionBeginHot; 5720 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5721 PetscCall(DMGetField(dm, field, NULL, &obj)); 5722 PetscCall(PetscObjectGetClassId(obj, &id)); 5723 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5724 5725 if (!fe) { 5726 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5727 /* An order k SEM disc has k-1 dofs on an edge */ 5728 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5729 *k = *k / *Nc + 1; 5730 } else { 5731 PetscInt dual_space_size, dim; 5732 PetscDualSpace dsp; 5733 5734 PetscCall(DMGetDimension(dm, &dim)); 5735 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5736 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5737 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5738 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5739 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5740 } 5741 PetscFunctionReturn(PETSC_SUCCESS); 5742 } 5743 5744 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5745 { 5746 PetscFunctionBeginHot; 5747 if (tensor) { 5748 *dof = PetscPowInt(k + 1, dim); 5749 } else { 5750 switch (dim) { 5751 case 1: 5752 *dof = k + 1; 5753 break; 5754 case 2: 5755 *dof = ((k + 1) * (k + 2)) / 2; 5756 break; 5757 case 3: 5758 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5759 break; 5760 default: 5761 *dof = 0; 5762 } 5763 } 5764 PetscFunctionReturn(PETSC_SUCCESS); 5765 } 5766 5767 /*@ 5768 5769 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5770 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5771 section provided (or the section of the `DM`). 5772 5773 Input Parameters: 5774 + dm - The `DM` 5775 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5776 - section - The `PetscSection` to reorder, or `NULL` for the default section 5777 5778 Example: 5779 A typical interpolated single-quad mesh might order points as 5780 .vb 5781 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5782 5783 v4 -- e6 -- v3 5784 | | 5785 e7 c0 e8 5786 | | 5787 v1 -- e5 -- v2 5788 .ve 5789 5790 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5791 dofs in the order of points, e.g., 5792 .vb 5793 c0 -> [0,1,2,3] 5794 v1 -> [4] 5795 ... 5796 e5 -> [8, 9] 5797 .ve 5798 5799 which corresponds to the dofs 5800 .vb 5801 6 10 11 7 5802 13 2 3 15 5803 12 0 1 14 5804 4 8 9 5 5805 .ve 5806 5807 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5808 .vb 5809 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5810 .ve 5811 5812 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5813 .vb 5814 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5815 .ve 5816 5817 Level: developer 5818 5819 Notes: 5820 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5821 degree of the basis. 5822 5823 This is required to run with libCEED. 5824 5825 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5826 @*/ 5827 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5828 { 5829 DMLabel label; 5830 PetscInt dim, depth = -1, eStart = -1, Nf; 5831 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5832 5833 PetscFunctionBegin; 5834 PetscCall(DMGetDimension(dm, &dim)); 5835 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5836 if (point < 0) { 5837 PetscInt sStart, sEnd; 5838 5839 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5840 point = sEnd - sStart ? sStart : point; 5841 } 5842 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5843 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5844 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5845 if (depth == 1) { 5846 eStart = point; 5847 } else if (depth == dim) { 5848 const PetscInt *cone; 5849 5850 PetscCall(DMPlexGetCone(dm, point, &cone)); 5851 if (dim == 2) eStart = cone[0]; 5852 else if (dim == 3) { 5853 const PetscInt *cone2; 5854 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5855 eStart = cone2[0]; 5856 } 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); 5857 } 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); 5858 5859 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5860 for (PetscInt d = 1; d <= dim; d++) { 5861 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5862 PetscInt *perm; 5863 5864 for (f = 0; f < Nf; ++f) { 5865 PetscInt dof; 5866 5867 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5868 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5869 if (!continuous && d < dim) continue; 5870 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5871 size += dof * Nc; 5872 } 5873 PetscCall(PetscMalloc1(size, &perm)); 5874 for (f = 0; f < Nf; ++f) { 5875 switch (d) { 5876 case 1: 5877 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5878 if (!continuous && d < dim) continue; 5879 /* 5880 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5881 We want [ vtx0; edge of length k-1; vtx1 ] 5882 */ 5883 if (continuous) { 5884 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5885 for (i = 0; i < k - 1; i++) 5886 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5887 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5888 foffset = offset; 5889 } else { 5890 PetscInt dof; 5891 5892 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5893 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5894 foffset = offset; 5895 } 5896 break; 5897 case 2: 5898 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5899 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5900 if (!continuous && d < dim) continue; 5901 /* The SEM order is 5902 5903 v_lb, {e_b}, v_rb, 5904 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5905 v_lt, reverse {e_t}, v_rt 5906 */ 5907 if (continuous) { 5908 const PetscInt of = 0; 5909 const PetscInt oeb = of + PetscSqr(k - 1); 5910 const PetscInt oer = oeb + (k - 1); 5911 const PetscInt oet = oer + (k - 1); 5912 const PetscInt oel = oet + (k - 1); 5913 const PetscInt ovlb = oel + (k - 1); 5914 const PetscInt ovrb = ovlb + 1; 5915 const PetscInt ovrt = ovrb + 1; 5916 const PetscInt ovlt = ovrt + 1; 5917 PetscInt o; 5918 5919 /* bottom */ 5920 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5921 for (o = oeb; o < oer; ++o) 5922 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5923 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5924 /* middle */ 5925 for (i = 0; i < k - 1; ++i) { 5926 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5927 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5928 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5929 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5930 } 5931 /* top */ 5932 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5933 for (o = oel - 1; o >= oet; --o) 5934 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5935 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5936 foffset = offset; 5937 } else { 5938 PetscInt dof; 5939 5940 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5941 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5942 foffset = offset; 5943 } 5944 break; 5945 case 3: 5946 /* The original hex closure is 5947 5948 {c, 5949 f_b, f_t, f_f, f_b, f_r, f_l, 5950 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5951 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5952 */ 5953 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5954 if (!continuous && d < dim) continue; 5955 /* The SEM order is 5956 Bottom Slice 5957 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5958 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5959 v_blb, {e_bb}, v_brb, 5960 5961 Middle Slice (j) 5962 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5963 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5964 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5965 5966 Top Slice 5967 v_tlf, {e_tf}, v_trf, 5968 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5969 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5970 */ 5971 if (continuous) { 5972 const PetscInt oc = 0; 5973 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5974 const PetscInt oft = ofb + PetscSqr(k - 1); 5975 const PetscInt off = oft + PetscSqr(k - 1); 5976 const PetscInt ofk = off + PetscSqr(k - 1); 5977 const PetscInt ofr = ofk + PetscSqr(k - 1); 5978 const PetscInt ofl = ofr + PetscSqr(k - 1); 5979 const PetscInt oebl = ofl + PetscSqr(k - 1); 5980 const PetscInt oebb = oebl + (k - 1); 5981 const PetscInt oebr = oebb + (k - 1); 5982 const PetscInt oebf = oebr + (k - 1); 5983 const PetscInt oetf = oebf + (k - 1); 5984 const PetscInt oetr = oetf + (k - 1); 5985 const PetscInt oetb = oetr + (k - 1); 5986 const PetscInt oetl = oetb + (k - 1); 5987 const PetscInt oerf = oetl + (k - 1); 5988 const PetscInt oelf = oerf + (k - 1); 5989 const PetscInt oelb = oelf + (k - 1); 5990 const PetscInt oerb = oelb + (k - 1); 5991 const PetscInt ovblf = oerb + (k - 1); 5992 const PetscInt ovblb = ovblf + 1; 5993 const PetscInt ovbrb = ovblb + 1; 5994 const PetscInt ovbrf = ovbrb + 1; 5995 const PetscInt ovtlf = ovbrf + 1; 5996 const PetscInt ovtrf = ovtlf + 1; 5997 const PetscInt ovtrb = ovtrf + 1; 5998 const PetscInt ovtlb = ovtrb + 1; 5999 PetscInt o, n; 6000 6001 /* Bottom Slice */ 6002 /* bottom */ 6003 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6004 for (o = oetf - 1; o >= oebf; --o) 6005 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6006 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6007 /* middle */ 6008 for (i = 0; i < k - 1; ++i) { 6009 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6010 for (n = 0; n < k - 1; ++n) { 6011 o = ofb + n * (k - 1) + i; 6012 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6013 } 6014 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6015 } 6016 /* top */ 6017 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6018 for (o = oebb; o < oebr; ++o) 6019 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6020 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6021 6022 /* Middle Slice */ 6023 for (j = 0; j < k - 1; ++j) { 6024 /* bottom */ 6025 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6026 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6027 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6028 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6029 /* middle */ 6030 for (i = 0; i < k - 1; ++i) { 6031 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6032 for (n = 0; n < k - 1; ++n) 6033 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6034 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6035 } 6036 /* top */ 6037 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6038 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6039 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6040 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6041 } 6042 6043 /* Top Slice */ 6044 /* bottom */ 6045 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6046 for (o = oetf; o < oetr; ++o) 6047 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6048 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6049 /* middle */ 6050 for (i = 0; i < k - 1; ++i) { 6051 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6052 for (n = 0; n < k - 1; ++n) 6053 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6054 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6055 } 6056 /* top */ 6057 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6058 for (o = oetl - 1; o >= oetb; --o) 6059 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6060 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6061 6062 foffset = offset; 6063 } else { 6064 PetscInt dof; 6065 6066 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6067 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6068 foffset = offset; 6069 } 6070 break; 6071 default: 6072 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6073 } 6074 } 6075 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6076 /* Check permutation */ 6077 { 6078 PetscInt *check; 6079 6080 PetscCall(PetscMalloc1(size, &check)); 6081 for (i = 0; i < size; ++i) { 6082 check[i] = -1; 6083 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6084 } 6085 for (i = 0; i < size; ++i) check[perm[i]] = i; 6086 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6087 PetscCall(PetscFree(check)); 6088 } 6089 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6090 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6091 PetscInt *loc_perm; 6092 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6093 for (PetscInt i = 0; i < size; i++) { 6094 loc_perm[i] = perm[i]; 6095 loc_perm[size + i] = size + perm[i]; 6096 } 6097 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6098 } 6099 } 6100 PetscFunctionReturn(PETSC_SUCCESS); 6101 } 6102 6103 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6104 { 6105 PetscDS prob; 6106 PetscInt depth, Nf, h; 6107 DMLabel label; 6108 6109 PetscFunctionBeginHot; 6110 PetscCall(DMGetDS(dm, &prob)); 6111 Nf = prob->Nf; 6112 label = dm->depthLabel; 6113 *dspace = NULL; 6114 if (field < Nf) { 6115 PetscObject disc = prob->disc[field]; 6116 6117 if (disc->classid == PETSCFE_CLASSID) { 6118 PetscDualSpace dsp; 6119 6120 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6121 PetscCall(DMLabelGetNumValues(label, &depth)); 6122 PetscCall(DMLabelGetValue(label, point, &h)); 6123 h = depth - 1 - h; 6124 if (h) { 6125 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6126 } else { 6127 *dspace = dsp; 6128 } 6129 } 6130 } 6131 PetscFunctionReturn(PETSC_SUCCESS); 6132 } 6133 6134 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6135 { 6136 PetscScalar *array; 6137 const PetscScalar *vArray; 6138 const PetscInt *cone, *coneO; 6139 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6140 6141 PetscFunctionBeginHot; 6142 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6143 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6144 PetscCall(DMPlexGetCone(dm, point, &cone)); 6145 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6146 if (!values || !*values) { 6147 if ((point >= pStart) && (point < pEnd)) { 6148 PetscInt dof; 6149 6150 PetscCall(PetscSectionGetDof(section, point, &dof)); 6151 size += dof; 6152 } 6153 for (p = 0; p < numPoints; ++p) { 6154 const PetscInt cp = cone[p]; 6155 PetscInt dof; 6156 6157 if ((cp < pStart) || (cp >= pEnd)) continue; 6158 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6159 size += dof; 6160 } 6161 if (!values) { 6162 if (csize) *csize = size; 6163 PetscFunctionReturn(PETSC_SUCCESS); 6164 } 6165 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6166 } else { 6167 array = *values; 6168 } 6169 size = 0; 6170 PetscCall(VecGetArrayRead(v, &vArray)); 6171 if ((point >= pStart) && (point < pEnd)) { 6172 PetscInt dof, off, d; 6173 const PetscScalar *varr; 6174 6175 PetscCall(PetscSectionGetDof(section, point, &dof)); 6176 PetscCall(PetscSectionGetOffset(section, point, &off)); 6177 varr = PetscSafePointerPlusOffset(vArray, off); 6178 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6179 size += dof; 6180 } 6181 for (p = 0; p < numPoints; ++p) { 6182 const PetscInt cp = cone[p]; 6183 PetscInt o = coneO[p]; 6184 PetscInt dof, off, d; 6185 const PetscScalar *varr; 6186 6187 if ((cp < pStart) || (cp >= pEnd)) continue; 6188 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6189 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6190 varr = PetscSafePointerPlusOffset(vArray, off); 6191 if (o >= 0) { 6192 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6193 } else { 6194 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6195 } 6196 size += dof; 6197 } 6198 PetscCall(VecRestoreArrayRead(v, &vArray)); 6199 if (!*values) { 6200 if (csize) *csize = size; 6201 *values = array; 6202 } else { 6203 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6204 *csize = size; 6205 } 6206 PetscFunctionReturn(PETSC_SUCCESS); 6207 } 6208 6209 /* Compress out points not in the section */ 6210 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6211 { 6212 const PetscInt np = *numPoints; 6213 PetscInt pStart, pEnd, p, q; 6214 6215 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6216 for (p = 0, q = 0; p < np; ++p) { 6217 const PetscInt r = points[p * 2]; 6218 if ((r >= pStart) && (r < pEnd)) { 6219 points[q * 2] = r; 6220 points[q * 2 + 1] = points[p * 2 + 1]; 6221 ++q; 6222 } 6223 } 6224 *numPoints = q; 6225 return PETSC_SUCCESS; 6226 } 6227 6228 /* Compressed closure does not apply closure permutation */ 6229 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6230 { 6231 const PetscInt *cla = NULL; 6232 PetscInt np, *pts = NULL; 6233 6234 PetscFunctionBeginHot; 6235 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6236 if (!ornt && *clPoints) { 6237 PetscInt dof, off; 6238 6239 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6240 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6241 PetscCall(ISGetIndices(*clPoints, &cla)); 6242 np = dof / 2; 6243 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6244 } else { 6245 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6246 PetscCall(CompressPoints_Private(section, &np, pts)); 6247 } 6248 *numPoints = np; 6249 *points = pts; 6250 *clp = cla; 6251 PetscFunctionReturn(PETSC_SUCCESS); 6252 } 6253 6254 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6255 { 6256 PetscFunctionBeginHot; 6257 if (!*clPoints) { 6258 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6259 } else { 6260 PetscCall(ISRestoreIndices(*clPoints, clp)); 6261 } 6262 *numPoints = 0; 6263 *points = NULL; 6264 *clSec = NULL; 6265 *clPoints = NULL; 6266 *clp = NULL; 6267 PetscFunctionReturn(PETSC_SUCCESS); 6268 } 6269 6270 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6271 { 6272 PetscInt offset = 0, p; 6273 const PetscInt **perms = NULL; 6274 const PetscScalar **flips = NULL; 6275 6276 PetscFunctionBeginHot; 6277 *size = 0; 6278 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6279 for (p = 0; p < numPoints; p++) { 6280 const PetscInt point = points[2 * p]; 6281 const PetscInt *perm = perms ? perms[p] : NULL; 6282 const PetscScalar *flip = flips ? flips[p] : NULL; 6283 PetscInt dof, off, d; 6284 const PetscScalar *varr; 6285 6286 PetscCall(PetscSectionGetDof(section, point, &dof)); 6287 PetscCall(PetscSectionGetOffset(section, point, &off)); 6288 varr = PetscSafePointerPlusOffset(vArray, off); 6289 if (clperm) { 6290 if (perm) { 6291 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6292 } else { 6293 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6294 } 6295 if (flip) { 6296 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6297 } 6298 } else { 6299 if (perm) { 6300 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6301 } else { 6302 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6303 } 6304 if (flip) { 6305 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6306 } 6307 } 6308 offset += dof; 6309 } 6310 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6311 *size = offset; 6312 PetscFunctionReturn(PETSC_SUCCESS); 6313 } 6314 6315 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[]) 6316 { 6317 PetscInt offset = 0, f; 6318 6319 PetscFunctionBeginHot; 6320 *size = 0; 6321 for (f = 0; f < numFields; ++f) { 6322 PetscInt p; 6323 const PetscInt **perms = NULL; 6324 const PetscScalar **flips = NULL; 6325 6326 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6327 for (p = 0; p < numPoints; p++) { 6328 const PetscInt point = points[2 * p]; 6329 PetscInt fdof, foff, b; 6330 const PetscScalar *varr; 6331 const PetscInt *perm = perms ? perms[p] : NULL; 6332 const PetscScalar *flip = flips ? flips[p] : NULL; 6333 6334 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6335 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6336 varr = &vArray[foff]; 6337 if (clperm) { 6338 if (perm) { 6339 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6340 } else { 6341 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6342 } 6343 if (flip) { 6344 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6345 } 6346 } else { 6347 if (perm) { 6348 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6349 } else { 6350 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6351 } 6352 if (flip) { 6353 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6354 } 6355 } 6356 offset += fdof; 6357 } 6358 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6359 } 6360 *size = offset; 6361 PetscFunctionReturn(PETSC_SUCCESS); 6362 } 6363 6364 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6365 { 6366 PetscSection clSection; 6367 IS clPoints; 6368 PetscInt *points = NULL; 6369 const PetscInt *clp, *perm = NULL; 6370 PetscInt depth, numFields, numPoints, asize; 6371 6372 PetscFunctionBeginHot; 6373 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6374 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6375 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6376 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6377 PetscCall(DMPlexGetDepth(dm, &depth)); 6378 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6379 if (depth == 1 && numFields < 2) { 6380 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6381 PetscFunctionReturn(PETSC_SUCCESS); 6382 } 6383 /* Get points */ 6384 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6385 /* Get sizes */ 6386 asize = 0; 6387 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6388 PetscInt dof; 6389 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6390 asize += dof; 6391 } 6392 if (values) { 6393 const PetscScalar *vArray; 6394 PetscInt size; 6395 6396 if (*values) { 6397 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); 6398 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6399 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6400 PetscCall(VecGetArrayRead(v, &vArray)); 6401 /* Get values */ 6402 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6403 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6404 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6405 /* Cleanup array */ 6406 PetscCall(VecRestoreArrayRead(v, &vArray)); 6407 } 6408 if (csize) *csize = asize; 6409 /* Cleanup points */ 6410 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6411 PetscFunctionReturn(PETSC_SUCCESS); 6412 } 6413 6414 /*@C 6415 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6416 6417 Not collective 6418 6419 Input Parameters: 6420 + dm - The `DM` 6421 . section - The section describing the layout in `v`, or `NULL` to use the default section 6422 . v - The local vector 6423 - point - The point in the `DM` 6424 6425 Input/Output Parameters: 6426 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6427 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6428 if the user provided `NULL`, it is a borrowed array and should not be freed 6429 6430 Level: intermediate 6431 6432 Notes: 6433 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6434 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6435 assembly function, and a user may already have allocated storage for this operation. 6436 6437 A typical use could be 6438 .vb 6439 values = NULL; 6440 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6441 for (cl = 0; cl < clSize; ++cl) { 6442 <Compute on closure> 6443 } 6444 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6445 .ve 6446 or 6447 .vb 6448 PetscMalloc1(clMaxSize, &values); 6449 for (p = pStart; p < pEnd; ++p) { 6450 clSize = clMaxSize; 6451 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6452 for (cl = 0; cl < clSize; ++cl) { 6453 <Compute on closure> 6454 } 6455 } 6456 PetscFree(values); 6457 .ve 6458 6459 Fortran Notes: 6460 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6461 6462 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6463 @*/ 6464 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6465 { 6466 PetscFunctionBeginHot; 6467 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6468 PetscFunctionReturn(PETSC_SUCCESS); 6469 } 6470 6471 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6472 { 6473 DMLabel depthLabel; 6474 PetscSection clSection; 6475 IS clPoints; 6476 PetscScalar *array; 6477 const PetscScalar *vArray; 6478 PetscInt *points = NULL; 6479 const PetscInt *clp, *perm = NULL; 6480 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6481 6482 PetscFunctionBeginHot; 6483 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6484 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6485 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6486 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6487 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6488 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6489 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6490 if (mdepth == 1 && numFields < 2) { 6491 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6492 PetscFunctionReturn(PETSC_SUCCESS); 6493 } 6494 /* Get points */ 6495 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6496 for (clsize = 0, p = 0; p < Np; p++) { 6497 PetscInt dof; 6498 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6499 clsize += dof; 6500 } 6501 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6502 /* Filter points */ 6503 for (p = 0; p < numPoints * 2; p += 2) { 6504 PetscInt dep; 6505 6506 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6507 if (dep != depth) continue; 6508 points[Np * 2 + 0] = points[p]; 6509 points[Np * 2 + 1] = points[p + 1]; 6510 ++Np; 6511 } 6512 /* Get array */ 6513 if (!values || !*values) { 6514 PetscInt asize = 0, dof; 6515 6516 for (p = 0; p < Np * 2; p += 2) { 6517 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6518 asize += dof; 6519 } 6520 if (!values) { 6521 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6522 if (csize) *csize = asize; 6523 PetscFunctionReturn(PETSC_SUCCESS); 6524 } 6525 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6526 } else { 6527 array = *values; 6528 } 6529 PetscCall(VecGetArrayRead(v, &vArray)); 6530 /* Get values */ 6531 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6532 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6533 /* Cleanup points */ 6534 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6535 /* Cleanup array */ 6536 PetscCall(VecRestoreArrayRead(v, &vArray)); 6537 if (!*values) { 6538 if (csize) *csize = size; 6539 *values = array; 6540 } else { 6541 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6542 *csize = size; 6543 } 6544 PetscFunctionReturn(PETSC_SUCCESS); 6545 } 6546 6547 /*@C 6548 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6549 6550 Not collective 6551 6552 Input Parameters: 6553 + dm - The `DM` 6554 . section - The section describing the layout in `v`, or `NULL` to use the default section 6555 . v - The local vector 6556 . point - The point in the `DM` 6557 . csize - The number of values in the closure, or `NULL` 6558 - values - The array of values, which is a borrowed array and should not be freed 6559 6560 Level: intermediate 6561 6562 Note: 6563 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6564 6565 Fortran Notes: 6566 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6567 6568 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6569 @*/ 6570 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6571 { 6572 PetscInt size = 0; 6573 6574 PetscFunctionBegin; 6575 /* Should work without recalculating size */ 6576 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6577 *values = NULL; 6578 PetscFunctionReturn(PETSC_SUCCESS); 6579 } 6580 6581 static inline void add(PetscScalar *x, PetscScalar y) 6582 { 6583 *x += y; 6584 } 6585 static inline void insert(PetscScalar *x, PetscScalar y) 6586 { 6587 *x = y; 6588 } 6589 6590 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[]) 6591 { 6592 PetscInt cdof; /* The number of constraints on this point */ 6593 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6594 PetscScalar *a; 6595 PetscInt off, cind = 0, k; 6596 6597 PetscFunctionBegin; 6598 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6599 PetscCall(PetscSectionGetOffset(section, point, &off)); 6600 a = &array[off]; 6601 if (!cdof || setBC) { 6602 if (clperm) { 6603 if (perm) { 6604 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6605 } else { 6606 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6607 } 6608 } else { 6609 if (perm) { 6610 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6611 } else { 6612 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6613 } 6614 } 6615 } else { 6616 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6617 if (clperm) { 6618 if (perm) { 6619 for (k = 0; k < dof; ++k) { 6620 if ((cind < cdof) && (k == cdofs[cind])) { 6621 ++cind; 6622 continue; 6623 } 6624 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6625 } 6626 } else { 6627 for (k = 0; k < dof; ++k) { 6628 if ((cind < cdof) && (k == cdofs[cind])) { 6629 ++cind; 6630 continue; 6631 } 6632 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6633 } 6634 } 6635 } else { 6636 if (perm) { 6637 for (k = 0; k < dof; ++k) { 6638 if ((cind < cdof) && (k == cdofs[cind])) { 6639 ++cind; 6640 continue; 6641 } 6642 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6643 } 6644 } else { 6645 for (k = 0; k < dof; ++k) { 6646 if ((cind < cdof) && (k == cdofs[cind])) { 6647 ++cind; 6648 continue; 6649 } 6650 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6651 } 6652 } 6653 } 6654 } 6655 PetscFunctionReturn(PETSC_SUCCESS); 6656 } 6657 6658 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[]) 6659 { 6660 PetscInt cdof; /* The number of constraints on this point */ 6661 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6662 PetscScalar *a; 6663 PetscInt off, cind = 0, k; 6664 6665 PetscFunctionBegin; 6666 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6667 PetscCall(PetscSectionGetOffset(section, point, &off)); 6668 a = &array[off]; 6669 if (cdof) { 6670 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6671 if (clperm) { 6672 if (perm) { 6673 for (k = 0; k < dof; ++k) { 6674 if ((cind < cdof) && (k == cdofs[cind])) { 6675 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6676 cind++; 6677 } 6678 } 6679 } else { 6680 for (k = 0; k < dof; ++k) { 6681 if ((cind < cdof) && (k == cdofs[cind])) { 6682 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6683 cind++; 6684 } 6685 } 6686 } 6687 } else { 6688 if (perm) { 6689 for (k = 0; k < dof; ++k) { 6690 if ((cind < cdof) && (k == cdofs[cind])) { 6691 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6692 cind++; 6693 } 6694 } 6695 } else { 6696 for (k = 0; k < dof; ++k) { 6697 if ((cind < cdof) && (k == cdofs[cind])) { 6698 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6699 cind++; 6700 } 6701 } 6702 } 6703 } 6704 } 6705 PetscFunctionReturn(PETSC_SUCCESS); 6706 } 6707 6708 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[]) 6709 { 6710 PetscScalar *a; 6711 PetscInt fdof, foff, fcdof, foffset = *offset; 6712 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6713 PetscInt cind = 0, b; 6714 6715 PetscFunctionBegin; 6716 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6717 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6718 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6719 a = &array[foff]; 6720 if (!fcdof || setBC) { 6721 if (clperm) { 6722 if (perm) { 6723 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6724 } else { 6725 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6726 } 6727 } else { 6728 if (perm) { 6729 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6730 } else { 6731 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6732 } 6733 } 6734 } else { 6735 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6736 if (clperm) { 6737 if (perm) { 6738 for (b = 0; b < fdof; b++) { 6739 if ((cind < fcdof) && (b == fcdofs[cind])) { 6740 ++cind; 6741 continue; 6742 } 6743 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6744 } 6745 } else { 6746 for (b = 0; b < fdof; b++) { 6747 if ((cind < fcdof) && (b == fcdofs[cind])) { 6748 ++cind; 6749 continue; 6750 } 6751 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6752 } 6753 } 6754 } else { 6755 if (perm) { 6756 for (b = 0; b < fdof; b++) { 6757 if ((cind < fcdof) && (b == fcdofs[cind])) { 6758 ++cind; 6759 continue; 6760 } 6761 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6762 } 6763 } else { 6764 for (b = 0; b < fdof; b++) { 6765 if ((cind < fcdof) && (b == fcdofs[cind])) { 6766 ++cind; 6767 continue; 6768 } 6769 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6770 } 6771 } 6772 } 6773 } 6774 *offset += fdof; 6775 PetscFunctionReturn(PETSC_SUCCESS); 6776 } 6777 6778 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[]) 6779 { 6780 PetscScalar *a; 6781 PetscInt fdof, foff, fcdof, foffset = *offset; 6782 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6783 PetscInt Nc, cind = 0, ncind = 0, b; 6784 PetscBool ncSet, fcSet; 6785 6786 PetscFunctionBegin; 6787 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6788 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6789 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6790 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6791 a = &array[foff]; 6792 if (fcdof) { 6793 /* We just override fcdof and fcdofs with Ncc and comps */ 6794 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6795 if (clperm) { 6796 if (perm) { 6797 if (comps) { 6798 for (b = 0; b < fdof; b++) { 6799 ncSet = fcSet = PETSC_FALSE; 6800 if (b % Nc == comps[ncind]) { 6801 ncind = (ncind + 1) % Ncc; 6802 ncSet = PETSC_TRUE; 6803 } 6804 if ((cind < fcdof) && (b == fcdofs[cind])) { 6805 ++cind; 6806 fcSet = PETSC_TRUE; 6807 } 6808 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6809 } 6810 } else { 6811 for (b = 0; b < fdof; b++) { 6812 if ((cind < fcdof) && (b == fcdofs[cind])) { 6813 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6814 ++cind; 6815 } 6816 } 6817 } 6818 } else { 6819 if (comps) { 6820 for (b = 0; b < fdof; b++) { 6821 ncSet = fcSet = PETSC_FALSE; 6822 if (b % Nc == comps[ncind]) { 6823 ncind = (ncind + 1) % Ncc; 6824 ncSet = PETSC_TRUE; 6825 } 6826 if ((cind < fcdof) && (b == fcdofs[cind])) { 6827 ++cind; 6828 fcSet = PETSC_TRUE; 6829 } 6830 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6831 } 6832 } else { 6833 for (b = 0; b < fdof; b++) { 6834 if ((cind < fcdof) && (b == fcdofs[cind])) { 6835 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6836 ++cind; 6837 } 6838 } 6839 } 6840 } 6841 } else { 6842 if (perm) { 6843 if (comps) { 6844 for (b = 0; b < fdof; b++) { 6845 ncSet = fcSet = PETSC_FALSE; 6846 if (b % Nc == comps[ncind]) { 6847 ncind = (ncind + 1) % Ncc; 6848 ncSet = PETSC_TRUE; 6849 } 6850 if ((cind < fcdof) && (b == fcdofs[cind])) { 6851 ++cind; 6852 fcSet = PETSC_TRUE; 6853 } 6854 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6855 } 6856 } else { 6857 for (b = 0; b < fdof; b++) { 6858 if ((cind < fcdof) && (b == fcdofs[cind])) { 6859 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6860 ++cind; 6861 } 6862 } 6863 } 6864 } else { 6865 if (comps) { 6866 for (b = 0; b < fdof; b++) { 6867 ncSet = fcSet = PETSC_FALSE; 6868 if (b % Nc == comps[ncind]) { 6869 ncind = (ncind + 1) % Ncc; 6870 ncSet = PETSC_TRUE; 6871 } 6872 if ((cind < fcdof) && (b == fcdofs[cind])) { 6873 ++cind; 6874 fcSet = PETSC_TRUE; 6875 } 6876 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6877 } 6878 } else { 6879 for (b = 0; b < fdof; b++) { 6880 if ((cind < fcdof) && (b == fcdofs[cind])) { 6881 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6882 ++cind; 6883 } 6884 } 6885 } 6886 } 6887 } 6888 } 6889 *offset += fdof; 6890 PetscFunctionReturn(PETSC_SUCCESS); 6891 } 6892 6893 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6894 { 6895 PetscScalar *array; 6896 const PetscInt *cone, *coneO; 6897 PetscInt pStart, pEnd, p, numPoints, off, dof; 6898 6899 PetscFunctionBeginHot; 6900 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6901 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6902 PetscCall(DMPlexGetCone(dm, point, &cone)); 6903 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6904 PetscCall(VecGetArray(v, &array)); 6905 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6906 const PetscInt cp = !p ? point : cone[p - 1]; 6907 const PetscInt o = !p ? 0 : coneO[p - 1]; 6908 6909 if ((cp < pStart) || (cp >= pEnd)) { 6910 dof = 0; 6911 continue; 6912 } 6913 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6914 /* ADD_VALUES */ 6915 { 6916 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6917 PetscScalar *a; 6918 PetscInt cdof, coff, cind = 0, k; 6919 6920 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6921 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6922 a = &array[coff]; 6923 if (!cdof) { 6924 if (o >= 0) { 6925 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6926 } else { 6927 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6928 } 6929 } else { 6930 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6931 if (o >= 0) { 6932 for (k = 0; k < dof; ++k) { 6933 if ((cind < cdof) && (k == cdofs[cind])) { 6934 ++cind; 6935 continue; 6936 } 6937 a[k] += values[off + k]; 6938 } 6939 } else { 6940 for (k = 0; k < dof; ++k) { 6941 if ((cind < cdof) && (k == cdofs[cind])) { 6942 ++cind; 6943 continue; 6944 } 6945 a[k] += values[off + dof - k - 1]; 6946 } 6947 } 6948 } 6949 } 6950 } 6951 PetscCall(VecRestoreArray(v, &array)); 6952 PetscFunctionReturn(PETSC_SUCCESS); 6953 } 6954 6955 /*@C 6956 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6957 6958 Not collective 6959 6960 Input Parameters: 6961 + dm - The `DM` 6962 . section - The section describing the layout in `v`, or `NULL` to use the default section 6963 . v - The local vector 6964 . point - The point in the `DM` 6965 . values - The array of values 6966 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6967 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6968 6969 Level: intermediate 6970 6971 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6972 @*/ 6973 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6974 { 6975 PetscSection clSection; 6976 IS clPoints; 6977 PetscScalar *array; 6978 PetscInt *points = NULL; 6979 const PetscInt *clp, *clperm = NULL; 6980 PetscInt depth, numFields, numPoints, p, clsize; 6981 6982 PetscFunctionBeginHot; 6983 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6984 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6985 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6986 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6987 PetscCall(DMPlexGetDepth(dm, &depth)); 6988 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6989 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6990 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6991 PetscFunctionReturn(PETSC_SUCCESS); 6992 } 6993 /* Get points */ 6994 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6995 for (clsize = 0, p = 0; p < numPoints; p++) { 6996 PetscInt dof; 6997 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6998 clsize += dof; 6999 } 7000 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7001 /* Get array */ 7002 PetscCall(VecGetArray(v, &array)); 7003 /* Get values */ 7004 if (numFields > 0) { 7005 PetscInt offset = 0, f; 7006 for (f = 0; f < numFields; ++f) { 7007 const PetscInt **perms = NULL; 7008 const PetscScalar **flips = NULL; 7009 7010 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7011 switch (mode) { 7012 case INSERT_VALUES: 7013 for (p = 0; p < numPoints; p++) { 7014 const PetscInt point = points[2 * p]; 7015 const PetscInt *perm = perms ? perms[p] : NULL; 7016 const PetscScalar *flip = flips ? flips[p] : NULL; 7017 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7018 } 7019 break; 7020 case INSERT_ALL_VALUES: 7021 for (p = 0; p < numPoints; p++) { 7022 const PetscInt point = points[2 * p]; 7023 const PetscInt *perm = perms ? perms[p] : NULL; 7024 const PetscScalar *flip = flips ? flips[p] : NULL; 7025 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7026 } 7027 break; 7028 case INSERT_BC_VALUES: 7029 for (p = 0; p < numPoints; p++) { 7030 const PetscInt point = points[2 * p]; 7031 const PetscInt *perm = perms ? perms[p] : NULL; 7032 const PetscScalar *flip = flips ? flips[p] : NULL; 7033 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7034 } 7035 break; 7036 case ADD_VALUES: 7037 for (p = 0; p < numPoints; p++) { 7038 const PetscInt point = points[2 * p]; 7039 const PetscInt *perm = perms ? perms[p] : NULL; 7040 const PetscScalar *flip = flips ? flips[p] : NULL; 7041 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7042 } 7043 break; 7044 case ADD_ALL_VALUES: 7045 for (p = 0; p < numPoints; p++) { 7046 const PetscInt point = points[2 * p]; 7047 const PetscInt *perm = perms ? perms[p] : NULL; 7048 const PetscScalar *flip = flips ? flips[p] : NULL; 7049 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7050 } 7051 break; 7052 case ADD_BC_VALUES: 7053 for (p = 0; p < numPoints; p++) { 7054 const PetscInt point = points[2 * p]; 7055 const PetscInt *perm = perms ? perms[p] : NULL; 7056 const PetscScalar *flip = flips ? flips[p] : NULL; 7057 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7058 } 7059 break; 7060 default: 7061 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7062 } 7063 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7064 } 7065 } else { 7066 PetscInt dof, off; 7067 const PetscInt **perms = NULL; 7068 const PetscScalar **flips = NULL; 7069 7070 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7071 switch (mode) { 7072 case INSERT_VALUES: 7073 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7074 const PetscInt point = points[2 * p]; 7075 const PetscInt *perm = perms ? perms[p] : NULL; 7076 const PetscScalar *flip = flips ? flips[p] : NULL; 7077 PetscCall(PetscSectionGetDof(section, point, &dof)); 7078 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7079 } 7080 break; 7081 case INSERT_ALL_VALUES: 7082 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7083 const PetscInt point = points[2 * p]; 7084 const PetscInt *perm = perms ? perms[p] : NULL; 7085 const PetscScalar *flip = flips ? flips[p] : NULL; 7086 PetscCall(PetscSectionGetDof(section, point, &dof)); 7087 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7088 } 7089 break; 7090 case INSERT_BC_VALUES: 7091 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7092 const PetscInt point = points[2 * p]; 7093 const PetscInt *perm = perms ? perms[p] : NULL; 7094 const PetscScalar *flip = flips ? flips[p] : NULL; 7095 PetscCall(PetscSectionGetDof(section, point, &dof)); 7096 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7097 } 7098 break; 7099 case ADD_VALUES: 7100 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7101 const PetscInt point = points[2 * p]; 7102 const PetscInt *perm = perms ? perms[p] : NULL; 7103 const PetscScalar *flip = flips ? flips[p] : NULL; 7104 PetscCall(PetscSectionGetDof(section, point, &dof)); 7105 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7106 } 7107 break; 7108 case ADD_ALL_VALUES: 7109 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7110 const PetscInt point = points[2 * p]; 7111 const PetscInt *perm = perms ? perms[p] : NULL; 7112 const PetscScalar *flip = flips ? flips[p] : NULL; 7113 PetscCall(PetscSectionGetDof(section, point, &dof)); 7114 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7115 } 7116 break; 7117 case ADD_BC_VALUES: 7118 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7119 const PetscInt point = points[2 * p]; 7120 const PetscInt *perm = perms ? perms[p] : NULL; 7121 const PetscScalar *flip = flips ? flips[p] : NULL; 7122 PetscCall(PetscSectionGetDof(section, point, &dof)); 7123 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7124 } 7125 break; 7126 default: 7127 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7128 } 7129 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7130 } 7131 /* Cleanup points */ 7132 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7133 /* Cleanup array */ 7134 PetscCall(VecRestoreArray(v, &array)); 7135 PetscFunctionReturn(PETSC_SUCCESS); 7136 } 7137 7138 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7139 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7140 { 7141 PetscFunctionBegin; 7142 *contains = PETSC_TRUE; 7143 if (label) { 7144 PetscInt fdof; 7145 7146 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7147 if (!*contains) { 7148 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7149 *offset += fdof; 7150 PetscFunctionReturn(PETSC_SUCCESS); 7151 } 7152 } 7153 PetscFunctionReturn(PETSC_SUCCESS); 7154 } 7155 7156 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7157 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) 7158 { 7159 PetscSection clSection; 7160 IS clPoints; 7161 PetscScalar *array; 7162 PetscInt *points = NULL; 7163 const PetscInt *clp; 7164 PetscInt numFields, numPoints, p; 7165 PetscInt offset = 0, f; 7166 7167 PetscFunctionBeginHot; 7168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7169 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7170 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7171 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7172 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7173 /* Get points */ 7174 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7175 /* Get array */ 7176 PetscCall(VecGetArray(v, &array)); 7177 /* Get values */ 7178 for (f = 0; f < numFields; ++f) { 7179 const PetscInt **perms = NULL; 7180 const PetscScalar **flips = NULL; 7181 PetscBool contains; 7182 7183 if (!fieldActive[f]) { 7184 for (p = 0; p < numPoints * 2; p += 2) { 7185 PetscInt fdof; 7186 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7187 offset += fdof; 7188 } 7189 continue; 7190 } 7191 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7192 switch (mode) { 7193 case INSERT_VALUES: 7194 for (p = 0; p < numPoints; p++) { 7195 const PetscInt point = points[2 * p]; 7196 const PetscInt *perm = perms ? perms[p] : NULL; 7197 const PetscScalar *flip = flips ? flips[p] : NULL; 7198 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7199 if (!contains) continue; 7200 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7201 } 7202 break; 7203 case INSERT_ALL_VALUES: 7204 for (p = 0; p < numPoints; p++) { 7205 const PetscInt point = points[2 * p]; 7206 const PetscInt *perm = perms ? perms[p] : NULL; 7207 const PetscScalar *flip = flips ? flips[p] : NULL; 7208 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7209 if (!contains) continue; 7210 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7211 } 7212 break; 7213 case INSERT_BC_VALUES: 7214 for (p = 0; p < numPoints; p++) { 7215 const PetscInt point = points[2 * p]; 7216 const PetscInt *perm = perms ? perms[p] : NULL; 7217 const PetscScalar *flip = flips ? flips[p] : NULL; 7218 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7219 if (!contains) continue; 7220 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7221 } 7222 break; 7223 case ADD_VALUES: 7224 for (p = 0; p < numPoints; p++) { 7225 const PetscInt point = points[2 * p]; 7226 const PetscInt *perm = perms ? perms[p] : NULL; 7227 const PetscScalar *flip = flips ? flips[p] : NULL; 7228 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7229 if (!contains) continue; 7230 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7231 } 7232 break; 7233 case ADD_ALL_VALUES: 7234 for (p = 0; p < numPoints; p++) { 7235 const PetscInt point = points[2 * p]; 7236 const PetscInt *perm = perms ? perms[p] : NULL; 7237 const PetscScalar *flip = flips ? flips[p] : NULL; 7238 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7239 if (!contains) continue; 7240 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7241 } 7242 break; 7243 default: 7244 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7245 } 7246 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7247 } 7248 /* Cleanup points */ 7249 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7250 /* Cleanup array */ 7251 PetscCall(VecRestoreArray(v, &array)); 7252 PetscFunctionReturn(PETSC_SUCCESS); 7253 } 7254 7255 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7256 { 7257 PetscMPIInt rank; 7258 PetscInt i, j; 7259 7260 PetscFunctionBegin; 7261 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7262 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7263 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7264 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7265 numCIndices = numCIndices ? numCIndices : numRIndices; 7266 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7267 for (i = 0; i < numRIndices; i++) { 7268 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7269 for (j = 0; j < numCIndices; j++) { 7270 #if defined(PETSC_USE_COMPLEX) 7271 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7272 #else 7273 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7274 #endif 7275 } 7276 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7277 } 7278 PetscFunctionReturn(PETSC_SUCCESS); 7279 } 7280 7281 /* 7282 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7283 7284 Input Parameters: 7285 + section - The section for this data layout 7286 . islocal - Is the section (and thus indices being requested) local or global? 7287 . point - The point contributing dofs with these indices 7288 . off - The global offset of this point 7289 . loff - The local offset of each field 7290 . setBC - The flag determining whether to include indices of boundary values 7291 . perm - A permutation of the dofs on this point, or NULL 7292 - indperm - A permutation of the entire indices array, or NULL 7293 7294 Output Parameter: 7295 . indices - Indices for dofs on this point 7296 7297 Level: developer 7298 7299 Note: The indices could be local or global, depending on the value of 'off'. 7300 */ 7301 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7302 { 7303 PetscInt dof; /* The number of unknowns on this point */ 7304 PetscInt cdof; /* The number of constraints on this point */ 7305 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7306 PetscInt cind = 0, k; 7307 7308 PetscFunctionBegin; 7309 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7310 PetscCall(PetscSectionGetDof(section, point, &dof)); 7311 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7312 if (!cdof || setBC) { 7313 for (k = 0; k < dof; ++k) { 7314 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7315 const PetscInt ind = indperm ? indperm[preind] : preind; 7316 7317 indices[ind] = off + k; 7318 } 7319 } else { 7320 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7321 for (k = 0; k < dof; ++k) { 7322 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7323 const PetscInt ind = indperm ? indperm[preind] : preind; 7324 7325 if ((cind < cdof) && (k == cdofs[cind])) { 7326 /* Insert check for returning constrained indices */ 7327 indices[ind] = -(off + k + 1); 7328 ++cind; 7329 } else { 7330 indices[ind] = off + k - (islocal ? 0 : cind); 7331 } 7332 } 7333 } 7334 *loff += dof; 7335 PetscFunctionReturn(PETSC_SUCCESS); 7336 } 7337 7338 /* 7339 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7340 7341 Input Parameters: 7342 + section - a section (global or local) 7343 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7344 . point - point within section 7345 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7346 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7347 . setBC - identify constrained (boundary condition) points via involution. 7348 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7349 . permsoff - offset 7350 - indperm - index permutation 7351 7352 Output Parameter: 7353 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7354 . indices - array to hold indices (as defined by section) of each dof associated with point 7355 7356 Notes: 7357 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7358 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7359 in the local vector. 7360 7361 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7362 significant). It is invalid to call with a global section and setBC=true. 7363 7364 Developer Note: 7365 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7366 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7367 offset could be obtained from the section instead of passing it explicitly as we do now. 7368 7369 Example: 7370 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7371 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7372 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7373 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. 7374 7375 Level: developer 7376 */ 7377 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[]) 7378 { 7379 PetscInt numFields, foff, f; 7380 7381 PetscFunctionBegin; 7382 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7383 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7384 for (f = 0, foff = 0; f < numFields; ++f) { 7385 PetscInt fdof, cfdof; 7386 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7387 PetscInt cind = 0, b; 7388 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7389 7390 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7391 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7392 if (!cfdof || setBC) { 7393 for (b = 0; b < fdof; ++b) { 7394 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7395 const PetscInt ind = indperm ? indperm[preind] : preind; 7396 7397 indices[ind] = off + foff + b; 7398 } 7399 } else { 7400 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7401 for (b = 0; b < fdof; ++b) { 7402 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7403 const PetscInt ind = indperm ? indperm[preind] : preind; 7404 7405 if ((cind < cfdof) && (b == fcdofs[cind])) { 7406 indices[ind] = -(off + foff + b + 1); 7407 ++cind; 7408 } else { 7409 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7410 } 7411 } 7412 } 7413 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7414 foffs[f] += fdof; 7415 } 7416 PetscFunctionReturn(PETSC_SUCCESS); 7417 } 7418 7419 /* 7420 This version believes the globalSection offsets for each field, rather than just the point offset 7421 7422 . foffs - The offset into 'indices' for each field, since it is segregated by field 7423 7424 Notes: 7425 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7426 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7427 */ 7428 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7429 { 7430 PetscInt numFields, foff, f; 7431 7432 PetscFunctionBegin; 7433 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7434 for (f = 0; f < numFields; ++f) { 7435 PetscInt fdof, cfdof; 7436 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7437 PetscInt cind = 0, b; 7438 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7439 7440 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7441 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7442 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7443 if (!cfdof) { 7444 for (b = 0; b < fdof; ++b) { 7445 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7446 const PetscInt ind = indperm ? indperm[preind] : preind; 7447 7448 indices[ind] = foff + b; 7449 } 7450 } else { 7451 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7452 for (b = 0; b < fdof; ++b) { 7453 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7454 const PetscInt ind = indperm ? indperm[preind] : preind; 7455 7456 if ((cind < cfdof) && (b == fcdofs[cind])) { 7457 indices[ind] = -(foff + b + 1); 7458 ++cind; 7459 } else { 7460 indices[ind] = foff + b - cind; 7461 } 7462 } 7463 } 7464 foffs[f] += fdof; 7465 } 7466 PetscFunctionReturn(PETSC_SUCCESS); 7467 } 7468 7469 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7470 { 7471 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7472 7473 PetscFunctionBegin; 7474 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7475 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7476 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7477 for (PetscInt p = 0; p < nPoints; p++) { 7478 PetscInt b = pnts[2 * p]; 7479 PetscInt bSecDof = 0, bOff; 7480 PetscInt cSecDof = 0; 7481 PetscSection indices_section; 7482 7483 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7484 if (!bSecDof) continue; 7485 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7486 indices_section = cSecDof > 0 ? cSec : section; 7487 if (numFields) { 7488 PetscInt fStart[32], fEnd[32]; 7489 7490 fStart[0] = 0; 7491 fEnd[0] = 0; 7492 for (PetscInt f = 0; f < numFields; f++) { 7493 PetscInt fDof = 0; 7494 7495 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7496 fStart[f + 1] = fStart[f] + fDof; 7497 fEnd[f + 1] = fStart[f + 1]; 7498 } 7499 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7500 // only apply permutations on one side 7501 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7502 for (PetscInt f = 0; f < numFields; f++) { 7503 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7504 } 7505 } else { 7506 PetscInt bEnd = 0; 7507 7508 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7509 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7510 7511 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7512 } 7513 } 7514 PetscFunctionReturn(PETSC_SUCCESS); 7515 } 7516 7517 PETSC_INTERN PetscErrorCode DMPlexAnchorsGetSubMatModification(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscInt offsets[], PetscScalar *outMat[]) 7518 { 7519 Mat cMat; 7520 PetscSection aSec, cSec; 7521 IS aIS; 7522 PetscInt aStart = -1, aEnd = -1; 7523 PetscInt sStart = -1, sEnd = -1; 7524 PetscInt cStart = -1, cEnd = -1; 7525 const PetscInt *anchors; 7526 PetscInt numFields, p; 7527 PetscInt newNumPoints = 0, newNumIndices = 0; 7528 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7529 PetscInt oldOffsets[32]; 7530 PetscInt newOffsets[32]; 7531 PetscInt oldOffsetsCopy[32]; 7532 PetscInt newOffsetsCopy[32]; 7533 PetscScalar *modMat = NULL; 7534 PetscBool anyConstrained = PETSC_FALSE; 7535 7536 PetscFunctionBegin; 7537 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7538 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7539 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7540 7541 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7542 /* if there are point-to-point constraints */ 7543 if (aSec) { 7544 PetscCall(PetscArrayzero(newOffsets, 32)); 7545 PetscCall(PetscArrayzero(oldOffsets, 32)); 7546 PetscCall(ISGetIndices(aIS, &anchors)); 7547 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7548 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7549 /* figure out how many points are going to be in the new element matrix 7550 * (we allow double counting, because it's all just going to be summed 7551 * into the global matrix anyway) */ 7552 for (p = 0; p < 2 * numPoints; p += 2) { 7553 PetscInt b = points[p]; 7554 PetscInt bDof = 0, bSecDof = 0; 7555 7556 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7557 if (!bSecDof) continue; 7558 7559 for (PetscInt f = 0; f < numFields; f++) { 7560 PetscInt fDof = 0; 7561 7562 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7563 oldOffsets[f + 1] += fDof; 7564 } 7565 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7566 if (bDof) { 7567 /* this point is constrained */ 7568 /* it is going to be replaced by its anchors */ 7569 PetscInt bOff, q; 7570 7571 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7572 for (q = 0; q < bDof; q++) { 7573 PetscInt a = anchors[bOff + q]; 7574 PetscInt aDof = 0; 7575 7576 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7577 if (aDof) { 7578 anyConstrained = PETSC_TRUE; 7579 newNumPoints += 1; 7580 } 7581 newNumIndices += aDof; 7582 for (PetscInt f = 0; f < numFields; ++f) { 7583 PetscInt fDof = 0; 7584 7585 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7586 newOffsets[f + 1] += fDof; 7587 } 7588 } 7589 } else { 7590 /* this point is not constrained */ 7591 newNumPoints++; 7592 newNumIndices += bSecDof; 7593 for (PetscInt f = 0; f < numFields; ++f) { 7594 PetscInt fDof; 7595 7596 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7597 newOffsets[f + 1] += fDof; 7598 } 7599 } 7600 } 7601 } 7602 if (!anyConstrained) { 7603 if (outNumPoints) *outNumPoints = 0; 7604 if (outNumIndices) *outNumIndices = 0; 7605 if (outPoints) *outPoints = NULL; 7606 if (outMat) *outMat = NULL; 7607 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7608 PetscFunctionReturn(PETSC_SUCCESS); 7609 } 7610 7611 if (outNumPoints) *outNumPoints = newNumPoints; 7612 if (outNumIndices) *outNumIndices = newNumIndices; 7613 7614 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7615 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7616 7617 if (!outPoints && !outMat) { 7618 if (offsets) { 7619 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7620 } 7621 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7622 PetscFunctionReturn(PETSC_SUCCESS); 7623 } 7624 7625 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7626 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7627 7628 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7629 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7630 7631 /* output arrays */ 7632 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7633 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7634 7635 // get the new Points 7636 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7637 PetscInt b = points[2 * p]; 7638 PetscInt bDof = 0, bSecDof = 0, bOff; 7639 7640 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7641 if (!bSecDof) continue; 7642 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7643 if (bDof) { 7644 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7645 for (PetscInt q = 0; q < bDof; q++) { 7646 PetscInt a = anchors[bOff + q], aDof = 0; 7647 7648 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7649 if (aDof) { 7650 newPoints[2 * newP] = a; 7651 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7652 newP++; 7653 } 7654 } 7655 } else { 7656 newPoints[2 * newP] = b; 7657 newPoints[2 * newP + 1] = points[2 * p + 1]; 7658 newP++; 7659 } 7660 } 7661 7662 if (outMat) { 7663 PetscScalar *tmpMat; 7664 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7665 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7666 7667 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7668 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7669 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7670 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7671 7672 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7673 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7674 7675 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7676 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7677 7678 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7679 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7680 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7681 // for each field, insert the anchor modification into modMat 7682 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7683 PetscInt fStart = oldOffsets[f]; 7684 PetscInt fNewStart = newOffsets[f]; 7685 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7686 PetscInt b = points[2 * p]; 7687 PetscInt bDof = 0, bSecDof = 0, bOff; 7688 7689 if (b >= sStart && b < sEnd) { 7690 if (numFields) { 7691 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7692 } else { 7693 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7694 } 7695 } 7696 if (!bSecDof) continue; 7697 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7698 if (bDof) { 7699 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7700 for (PetscInt q = 0; q < bDof; q++, newP++) { 7701 PetscInt a = anchors[bOff + q], aDof = 0; 7702 7703 if (a >= sStart && a < sEnd) { 7704 if (numFields) { 7705 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7706 } else { 7707 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7708 } 7709 } 7710 if (aDof) { 7711 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7712 for (PetscInt d = 0; d < bSecDof; d++) { 7713 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7714 } 7715 } 7716 oNew += aDof; 7717 } 7718 } else { 7719 // Insert the identity matrix in this block 7720 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7721 oNew += bSecDof; 7722 newP++; 7723 } 7724 o += bSecDof; 7725 } 7726 } 7727 7728 *outMat = modMat; 7729 7730 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7731 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7732 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7733 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7734 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7735 } 7736 PetscCall(ISRestoreIndices(aIS, &anchors)); 7737 7738 /* output */ 7739 if (outPoints) { 7740 *outPoints = newPoints; 7741 } else { 7742 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7743 } 7744 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7745 PetscFunctionReturn(PETSC_SUCCESS); 7746 } 7747 7748 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat_Internal(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt numRows, PetscInt numCols, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyRight, PetscBool multiplyLeft) 7749 { 7750 PetscScalar *modMat = NULL; 7751 PetscInt newNumIndices = -1; 7752 7753 PetscFunctionBegin; 7754 /* If M is the matrix represented by values, get the matrix C such that we will add M * C (or, if multiplyLeft, C^T * M * C) into the global matrix. 7755 modMat is that matrix C */ 7756 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7757 if (outNumIndices) *outNumIndices = newNumIndices; 7758 if (modMat) { 7759 const PetscScalar *newValues = values; 7760 7761 if (multiplyRight) { 7762 PetscScalar *newNewValues = NULL; 7763 PetscBLASInt M = newNumIndices; 7764 PetscBLASInt N = numRows; 7765 PetscBLASInt K = numIndices; 7766 PetscScalar a = 1.0, b = 0.0; 7767 7768 PetscCheck(numCols == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of columns: %" PetscInt_FMT ", expected %" PetscInt_FMT, numCols, numIndices); 7769 7770 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7771 // row-major to column-major conversion, right multiplication becomes left multiplication 7772 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7773 7774 numCols = newNumIndices; 7775 newValues = newNewValues; 7776 } 7777 7778 if (multiplyLeft) { 7779 PetscScalar *newNewValues = NULL; 7780 PetscBLASInt M = numCols; 7781 PetscBLASInt N = newNumIndices; 7782 PetscBLASInt K = numIndices; 7783 PetscScalar a = 1.0, b = 0.0; 7784 7785 PetscCheck(numRows == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of rows: %" PetscInt_FMT ", expected %" PetscInt_FMT, numRows, numIndices); 7786 7787 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7788 // row-major to column-major conversion, left multiplication becomes right multiplication 7789 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7790 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7791 newValues = newNewValues; 7792 } 7793 *outValues = (PetscScalar *)newValues; 7794 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7795 } 7796 PetscFunctionReturn(PETSC_SUCCESS); 7797 } 7798 7799 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft) 7800 { 7801 PetscFunctionBegin; 7802 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7803 PetscFunctionReturn(PETSC_SUCCESS); 7804 } 7805 7806 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7807 { 7808 /* Closure ordering */ 7809 PetscSection clSection; 7810 IS clPoints; 7811 const PetscInt *clp; 7812 PetscInt *points; 7813 PetscInt Ncl, Ni = 0; 7814 7815 PetscFunctionBeginHot; 7816 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7817 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7818 PetscInt dof; 7819 7820 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7821 Ni += dof; 7822 } 7823 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7824 *closureSize = Ni; 7825 PetscFunctionReturn(PETSC_SUCCESS); 7826 } 7827 7828 static PetscErrorCode DMPlexGetClosureIndices_Internal(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numRows, PetscInt *numCols, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[], PetscBool multiplyRight, PetscBool multiplyLeft) 7829 { 7830 /* Closure ordering */ 7831 PetscSection clSection; 7832 IS clPoints; 7833 const PetscInt *clp; 7834 PetscInt *points; 7835 const PetscInt *clperm = NULL; 7836 /* Dof permutation and sign flips */ 7837 const PetscInt **perms[32] = {NULL}; 7838 const PetscScalar **flips[32] = {NULL}; 7839 PetscScalar *valCopy = NULL; 7840 /* Hanging node constraints */ 7841 PetscInt *pointsC = NULL; 7842 PetscScalar *valuesC = NULL; 7843 PetscInt NclC, NiC; 7844 7845 PetscInt *idx; 7846 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7847 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7848 PetscInt idxStart, idxEnd; 7849 PetscInt nRows, nCols; 7850 7851 PetscFunctionBeginHot; 7852 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7853 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7854 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7855 PetscAssertPointer(numRows, 6); 7856 PetscAssertPointer(numCols, 7); 7857 if (indices) PetscAssertPointer(indices, 8); 7858 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7859 if (values) PetscAssertPointer(values, 10); 7860 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7861 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7862 PetscCall(PetscArrayzero(offsets, 32)); 7863 /* 1) Get points in closure */ 7864 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7865 if (useClPerm) { 7866 PetscInt depth, clsize; 7867 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7868 for (clsize = 0, p = 0; p < Ncl; p++) { 7869 PetscInt dof; 7870 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7871 clsize += dof; 7872 } 7873 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7874 } 7875 /* 2) Get number of indices on these points and field offsets from section */ 7876 for (p = 0; p < Ncl * 2; p += 2) { 7877 PetscInt dof, fdof; 7878 7879 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7880 for (f = 0; f < Nf; ++f) { 7881 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7882 offsets[f + 1] += fdof; 7883 } 7884 Ni += dof; 7885 } 7886 if (*numRows == -1) *numRows = Ni; 7887 if (*numCols == -1) *numCols = Ni; 7888 nRows = *numRows; 7889 nCols = *numCols; 7890 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7891 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7892 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7893 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7894 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7895 for (f = 0; f < PetscMax(1, Nf); ++f) { 7896 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7897 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7898 /* may need to apply sign changes to the element matrix */ 7899 if (values && flips[f]) { 7900 PetscInt foffset = offsets[f]; 7901 7902 for (p = 0; p < Ncl; ++p) { 7903 PetscInt pnt = points[2 * p], fdof; 7904 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7905 7906 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7907 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7908 if (flip) { 7909 PetscInt i, j, k; 7910 7911 if (!valCopy) { 7912 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7913 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7914 *values = valCopy; 7915 } 7916 for (i = 0; i < fdof; ++i) { 7917 PetscScalar fval = flip[i]; 7918 7919 if (multiplyRight) { 7920 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 7921 } 7922 if (multiplyLeft) { 7923 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 7924 } 7925 } 7926 } 7927 foffset += fdof; 7928 } 7929 } 7930 } 7931 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7932 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 7933 if (NclC) { 7934 if (multiplyRight) { *numCols = nCols = NiC; } 7935 if (multiplyLeft) { *numRows = nRows = NiC; } 7936 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7937 for (f = 0; f < PetscMax(1, Nf); ++f) { 7938 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7939 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7940 } 7941 for (f = 0; f < PetscMax(1, Nf); ++f) { 7942 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7943 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7944 } 7945 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7946 Ncl = NclC; 7947 Ni = NiC; 7948 points = pointsC; 7949 if (values) *values = valuesC; 7950 } 7951 /* 5) Calculate indices */ 7952 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7953 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 7954 if (Nf) { 7955 PetscInt idxOff; 7956 PetscBool useFieldOffsets; 7957 7958 if (outOffsets) { 7959 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7960 } 7961 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7962 if (useFieldOffsets) { 7963 for (p = 0; p < Ncl; ++p) { 7964 const PetscInt pnt = points[p * 2]; 7965 7966 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7967 } 7968 } else { 7969 for (p = 0; p < Ncl; ++p) { 7970 const PetscInt pnt = points[p * 2]; 7971 7972 if (pnt < idxStart || pnt >= idxEnd) continue; 7973 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7974 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7975 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7976 * global section. */ 7977 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7978 } 7979 } 7980 } else { 7981 PetscInt off = 0, idxOff; 7982 7983 for (p = 0; p < Ncl; ++p) { 7984 const PetscInt pnt = points[p * 2]; 7985 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7986 7987 if (pnt < idxStart || pnt >= idxEnd) continue; 7988 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7989 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7990 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7991 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7992 } 7993 } 7994 /* 6) Cleanup */ 7995 for (f = 0; f < PetscMax(1, Nf); ++f) { 7996 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7997 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7998 } 7999 if (NclC) { 8000 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8001 } else { 8002 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8003 } 8004 8005 if (indices) *indices = idx; 8006 PetscFunctionReturn(PETSC_SUCCESS); 8007 } 8008 8009 /*@C 8010 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8011 8012 Not collective 8013 8014 Input Parameters: 8015 + dm - The `DM` 8016 . section - The `PetscSection` describing the points (a local section) 8017 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8018 . point - The point defining the closure 8019 - useClPerm - Use the closure point permutation if available 8020 8021 Output Parameters: 8022 + numIndices - The number of dof indices in the closure of point with the input sections 8023 . indices - The dof indices 8024 . outOffsets - Array to write the field offsets into, or `NULL` 8025 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8026 8027 Level: advanced 8028 8029 Notes: 8030 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 8031 8032 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8033 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8034 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8035 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8036 indices (with the above semantics) are implied. 8037 8038 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8039 `PetscSection`, `DMGetGlobalSection()` 8040 @*/ 8041 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8042 { 8043 PetscInt numRows = -1, numCols = -1; 8044 8045 PetscFunctionBeginHot; 8046 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8047 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8048 *numIndices = numRows; 8049 PetscFunctionReturn(PETSC_SUCCESS); 8050 } 8051 8052 /*@C 8053 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8054 8055 Not collective 8056 8057 Input Parameters: 8058 + dm - The `DM` 8059 . section - The `PetscSection` describing the points (a local section) 8060 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8061 . point - The point defining the closure 8062 - useClPerm - Use the closure point permutation if available 8063 8064 Output Parameters: 8065 + numIndices - The number of dof indices in the closure of point with the input sections 8066 . indices - The dof indices 8067 . outOffsets - Array to write the field offsets into, or `NULL` 8068 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8069 8070 Level: advanced 8071 8072 Notes: 8073 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8074 8075 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8076 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8077 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8078 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8079 indices (with the above semantics) are implied. 8080 8081 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8082 @*/ 8083 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8084 { 8085 PetscFunctionBegin; 8086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8087 PetscAssertPointer(indices, 7); 8088 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8089 PetscFunctionReturn(PETSC_SUCCESS); 8090 } 8091 8092 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8093 { 8094 DM_Plex *mesh = (DM_Plex *)dm->data; 8095 PetscInt *indices; 8096 PetscInt numIndices; 8097 const PetscScalar *valuesOrig = values; 8098 PetscErrorCode ierr; 8099 8100 PetscFunctionBegin; 8101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8102 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8103 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8104 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8105 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8106 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8107 8108 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8109 8110 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8111 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8112 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8113 if (ierr) { 8114 PetscMPIInt rank; 8115 8116 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8117 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8118 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8119 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8120 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8121 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8122 } 8123 if (mesh->printFEM > 1) { 8124 PetscInt i; 8125 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8126 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8127 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8128 } 8129 8130 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8131 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8132 PetscFunctionReturn(PETSC_SUCCESS); 8133 } 8134 8135 /*@C 8136 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8137 8138 Not collective 8139 8140 Input Parameters: 8141 + dm - The `DM` 8142 . section - The section describing the layout in `v`, or `NULL` to use the default section 8143 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8144 . A - The matrix 8145 . point - The point in the `DM` 8146 . values - The array of values 8147 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8148 8149 Level: intermediate 8150 8151 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8152 @*/ 8153 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8154 { 8155 PetscFunctionBegin; 8156 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8157 PetscFunctionReturn(PETSC_SUCCESS); 8158 } 8159 8160 /*@C 8161 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8162 8163 Not collective 8164 8165 Input Parameters: 8166 + dmRow - The `DM` for the row fields 8167 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8168 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8169 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8170 . dmCol - The `DM` for the column fields 8171 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8172 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8173 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8174 . A - The matrix 8175 . point - The point in the `DM` 8176 . values - The array of values 8177 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8178 8179 Level: intermediate 8180 8181 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8182 @*/ 8183 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) 8184 { 8185 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8186 PetscInt *indicesRow, *indicesCol; 8187 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8188 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8189 8190 PetscErrorCode ierr; 8191 8192 PetscFunctionBegin; 8193 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8194 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8195 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8196 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8197 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8198 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8199 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8200 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8201 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8202 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8203 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8204 8205 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8206 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8207 valuesV1 = valuesV0; 8208 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8209 valuesV2 = valuesV1; 8210 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8211 8212 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8213 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8214 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8215 if (ierr) { 8216 PetscMPIInt rank; 8217 8218 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8219 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8220 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8221 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8222 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8223 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8224 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8225 } 8226 8227 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8228 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8229 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8230 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8231 PetscFunctionReturn(PETSC_SUCCESS); 8232 } 8233 8234 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8235 { 8236 DM_Plex *mesh = (DM_Plex *)dmf->data; 8237 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8238 PetscInt *cpoints = NULL; 8239 PetscInt *findices, *cindices; 8240 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8241 PetscInt foffsets[32], coffsets[32]; 8242 DMPolytopeType ct; 8243 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8244 PetscErrorCode ierr; 8245 8246 PetscFunctionBegin; 8247 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8248 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8249 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8250 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8251 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8252 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8253 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8254 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8255 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8256 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8257 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8258 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8259 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8260 PetscCall(PetscArrayzero(foffsets, 32)); 8261 PetscCall(PetscArrayzero(coffsets, 32)); 8262 /* Column indices */ 8263 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8264 maxFPoints = numCPoints; 8265 /* Compress out points not in the section */ 8266 /* TODO: Squeeze out points with 0 dof as well */ 8267 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8268 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8269 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8270 cpoints[q * 2] = cpoints[p]; 8271 cpoints[q * 2 + 1] = cpoints[p + 1]; 8272 ++q; 8273 } 8274 } 8275 numCPoints = q; 8276 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8277 PetscInt fdof; 8278 8279 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8280 if (!dof) continue; 8281 for (f = 0; f < numFields; ++f) { 8282 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8283 coffsets[f + 1] += fdof; 8284 } 8285 numCIndices += dof; 8286 } 8287 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8288 /* Row indices */ 8289 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8290 { 8291 DMPlexTransform tr; 8292 DMPolytopeType *rct; 8293 PetscInt *rsize, *rcone, *rornt, Nt; 8294 8295 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8296 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8297 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8298 numSubcells = rsize[Nt - 1]; 8299 PetscCall(DMPlexTransformDestroy(&tr)); 8300 } 8301 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8302 for (r = 0, q = 0; r < numSubcells; ++r) { 8303 /* TODO Map from coarse to fine cells */ 8304 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8305 /* Compress out points not in the section */ 8306 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8307 for (p = 0; p < numFPoints * 2; p += 2) { 8308 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8309 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8310 if (!dof) continue; 8311 for (s = 0; s < q; ++s) 8312 if (fpoints[p] == ftotpoints[s * 2]) break; 8313 if (s < q) continue; 8314 ftotpoints[q * 2] = fpoints[p]; 8315 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8316 ++q; 8317 } 8318 } 8319 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8320 } 8321 numFPoints = q; 8322 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8323 PetscInt fdof; 8324 8325 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8326 if (!dof) continue; 8327 for (f = 0; f < numFields; ++f) { 8328 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8329 foffsets[f + 1] += fdof; 8330 } 8331 numFIndices += dof; 8332 } 8333 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8334 8335 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8336 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8337 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8338 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8339 if (numFields) { 8340 const PetscInt **permsF[32] = {NULL}; 8341 const PetscInt **permsC[32] = {NULL}; 8342 8343 for (f = 0; f < numFields; f++) { 8344 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8345 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8346 } 8347 for (p = 0; p < numFPoints; p++) { 8348 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8349 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8350 } 8351 for (p = 0; p < numCPoints; p++) { 8352 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8353 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8354 } 8355 for (f = 0; f < numFields; f++) { 8356 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8357 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8358 } 8359 } else { 8360 const PetscInt **permsF = NULL; 8361 const PetscInt **permsC = NULL; 8362 8363 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8364 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8365 for (p = 0, off = 0; p < numFPoints; p++) { 8366 const PetscInt *perm = permsF ? permsF[p] : NULL; 8367 8368 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8369 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8370 } 8371 for (p = 0, off = 0; p < numCPoints; p++) { 8372 const PetscInt *perm = permsC ? permsC[p] : NULL; 8373 8374 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8375 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8376 } 8377 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8378 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8379 } 8380 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8381 /* TODO: flips */ 8382 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8383 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8384 if (ierr) { 8385 PetscMPIInt rank; 8386 8387 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8388 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8389 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8390 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8391 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8392 } 8393 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8394 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8395 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8396 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8397 PetscFunctionReturn(PETSC_SUCCESS); 8398 } 8399 8400 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8401 { 8402 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8403 PetscInt *cpoints = NULL; 8404 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8405 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8406 DMPolytopeType ct; 8407 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8408 8409 PetscFunctionBegin; 8410 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8411 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8412 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8413 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8414 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8415 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8416 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8417 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8418 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8419 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8420 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8421 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8422 /* Column indices */ 8423 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8424 maxFPoints = numCPoints; 8425 /* Compress out points not in the section */ 8426 /* TODO: Squeeze out points with 0 dof as well */ 8427 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8428 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8429 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8430 cpoints[q * 2] = cpoints[p]; 8431 cpoints[q * 2 + 1] = cpoints[p + 1]; 8432 ++q; 8433 } 8434 } 8435 numCPoints = q; 8436 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8437 PetscInt fdof; 8438 8439 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8440 if (!dof) continue; 8441 for (f = 0; f < numFields; ++f) { 8442 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8443 coffsets[f + 1] += fdof; 8444 } 8445 numCIndices += dof; 8446 } 8447 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8448 /* Row indices */ 8449 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8450 { 8451 DMPlexTransform tr; 8452 DMPolytopeType *rct; 8453 PetscInt *rsize, *rcone, *rornt, Nt; 8454 8455 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8456 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8457 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8458 numSubcells = rsize[Nt - 1]; 8459 PetscCall(DMPlexTransformDestroy(&tr)); 8460 } 8461 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8462 for (r = 0, q = 0; r < numSubcells; ++r) { 8463 /* TODO Map from coarse to fine cells */ 8464 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8465 /* Compress out points not in the section */ 8466 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8467 for (p = 0; p < numFPoints * 2; p += 2) { 8468 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8469 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8470 if (!dof) continue; 8471 for (s = 0; s < q; ++s) 8472 if (fpoints[p] == ftotpoints[s * 2]) break; 8473 if (s < q) continue; 8474 ftotpoints[q * 2] = fpoints[p]; 8475 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8476 ++q; 8477 } 8478 } 8479 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8480 } 8481 numFPoints = q; 8482 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8483 PetscInt fdof; 8484 8485 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8486 if (!dof) continue; 8487 for (f = 0; f < numFields; ++f) { 8488 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8489 foffsets[f + 1] += fdof; 8490 } 8491 numFIndices += dof; 8492 } 8493 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8494 8495 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8496 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8497 if (numFields) { 8498 const PetscInt **permsF[32] = {NULL}; 8499 const PetscInt **permsC[32] = {NULL}; 8500 8501 for (f = 0; f < numFields; f++) { 8502 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8503 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8504 } 8505 for (p = 0; p < numFPoints; p++) { 8506 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8507 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8508 } 8509 for (p = 0; p < numCPoints; p++) { 8510 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8511 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8512 } 8513 for (f = 0; f < numFields; f++) { 8514 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8515 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8516 } 8517 } else { 8518 const PetscInt **permsF = NULL; 8519 const PetscInt **permsC = NULL; 8520 8521 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8522 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8523 for (p = 0, off = 0; p < numFPoints; p++) { 8524 const PetscInt *perm = permsF ? permsF[p] : NULL; 8525 8526 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8527 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8528 } 8529 for (p = 0, off = 0; p < numCPoints; p++) { 8530 const PetscInt *perm = permsC ? permsC[p] : NULL; 8531 8532 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8533 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8534 } 8535 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8536 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8537 } 8538 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8539 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8540 PetscFunctionReturn(PETSC_SUCCESS); 8541 } 8542 8543 /*@C 8544 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8545 8546 Input Parameter: 8547 . dm - The `DMPLEX` object 8548 8549 Output Parameter: 8550 . cellHeight - The height of a cell 8551 8552 Level: developer 8553 8554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8555 @*/ 8556 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8557 { 8558 DM_Plex *mesh = (DM_Plex *)dm->data; 8559 8560 PetscFunctionBegin; 8561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8562 PetscAssertPointer(cellHeight, 2); 8563 *cellHeight = mesh->vtkCellHeight; 8564 PetscFunctionReturn(PETSC_SUCCESS); 8565 } 8566 8567 /*@C 8568 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8569 8570 Input Parameters: 8571 + dm - The `DMPLEX` object 8572 - cellHeight - The height of a cell 8573 8574 Level: developer 8575 8576 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8577 @*/ 8578 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8579 { 8580 DM_Plex *mesh = (DM_Plex *)dm->data; 8581 8582 PetscFunctionBegin; 8583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8584 mesh->vtkCellHeight = cellHeight; 8585 PetscFunctionReturn(PETSC_SUCCESS); 8586 } 8587 8588 /*@ 8589 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8590 8591 Input Parameters: 8592 + dm - The `DMPLEX` object 8593 - ct - The `DMPolytopeType` of the cell 8594 8595 Output Parameters: 8596 + start - The first cell of this type, or `NULL` 8597 - end - The upper bound on this celltype, or `NULL` 8598 8599 Level: advanced 8600 8601 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8602 @*/ 8603 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8604 { 8605 DM_Plex *mesh = (DM_Plex *)dm->data; 8606 DMLabel label; 8607 PetscInt pStart, pEnd; 8608 8609 PetscFunctionBegin; 8610 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8611 if (start) { 8612 PetscAssertPointer(start, 3); 8613 *start = 0; 8614 } 8615 if (end) { 8616 PetscAssertPointer(end, 4); 8617 *end = 0; 8618 } 8619 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8620 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8621 if (mesh->tr) { 8622 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8623 } else { 8624 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8625 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8626 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8627 } 8628 PetscFunctionReturn(PETSC_SUCCESS); 8629 } 8630 8631 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8632 { 8633 PetscSection section, globalSection; 8634 PetscInt *numbers, p; 8635 8636 PetscFunctionBegin; 8637 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8638 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8639 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8640 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8641 PetscCall(PetscSectionSetUp(section)); 8642 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8643 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8644 for (p = pStart; p < pEnd; ++p) { 8645 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8646 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8647 else numbers[p - pStart] += shift; 8648 } 8649 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8650 if (globalSize) { 8651 PetscLayout layout; 8652 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8653 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8654 PetscCall(PetscLayoutDestroy(&layout)); 8655 } 8656 PetscCall(PetscSectionDestroy(§ion)); 8657 PetscCall(PetscSectionDestroy(&globalSection)); 8658 PetscFunctionReturn(PETSC_SUCCESS); 8659 } 8660 8661 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8662 { 8663 PetscInt cellHeight, cStart, cEnd; 8664 8665 PetscFunctionBegin; 8666 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8667 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8668 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8669 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8670 PetscFunctionReturn(PETSC_SUCCESS); 8671 } 8672 8673 /*@ 8674 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8675 8676 Input Parameter: 8677 . dm - The `DMPLEX` object 8678 8679 Output Parameter: 8680 . globalCellNumbers - Global cell numbers for all cells on this process 8681 8682 Level: developer 8683 8684 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8685 @*/ 8686 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8687 { 8688 DM_Plex *mesh = (DM_Plex *)dm->data; 8689 8690 PetscFunctionBegin; 8691 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8692 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8693 *globalCellNumbers = mesh->globalCellNumbers; 8694 PetscFunctionReturn(PETSC_SUCCESS); 8695 } 8696 8697 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8698 { 8699 PetscInt vStart, vEnd; 8700 8701 PetscFunctionBegin; 8702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8703 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8704 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8705 PetscFunctionReturn(PETSC_SUCCESS); 8706 } 8707 8708 /*@ 8709 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8710 8711 Input Parameter: 8712 . dm - The `DMPLEX` object 8713 8714 Output Parameter: 8715 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8716 8717 Level: developer 8718 8719 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8720 @*/ 8721 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8722 { 8723 DM_Plex *mesh = (DM_Plex *)dm->data; 8724 8725 PetscFunctionBegin; 8726 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8727 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8728 *globalVertexNumbers = mesh->globalVertexNumbers; 8729 PetscFunctionReturn(PETSC_SUCCESS); 8730 } 8731 8732 /*@ 8733 DMPlexCreatePointNumbering - Create a global numbering for all points. 8734 8735 Collective 8736 8737 Input Parameter: 8738 . dm - The `DMPLEX` object 8739 8740 Output Parameter: 8741 . globalPointNumbers - Global numbers for all points on this process 8742 8743 Level: developer 8744 8745 Notes: 8746 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8747 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8748 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8749 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8750 8751 The partitioned mesh is 8752 ``` 8753 (2)--0--(3)--1--(4) (1)--0--(2) 8754 ``` 8755 and its global numbering is 8756 ``` 8757 (3)--0--(4)--1--(5)--2--(6) 8758 ``` 8759 Then the global numbering is provided as 8760 ``` 8761 [0] Number of indices in set 5 8762 [0] 0 0 8763 [0] 1 1 8764 [0] 2 3 8765 [0] 3 4 8766 [0] 4 -6 8767 [1] Number of indices in set 3 8768 [1] 0 2 8769 [1] 1 5 8770 [1] 2 6 8771 ``` 8772 8773 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8774 @*/ 8775 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8776 { 8777 IS nums[4]; 8778 PetscInt depths[4], gdepths[4], starts[4]; 8779 PetscInt depth, d, shift = 0; 8780 PetscBool empty = PETSC_FALSE; 8781 8782 PetscFunctionBegin; 8783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8784 PetscCall(DMPlexGetDepth(dm, &depth)); 8785 // For unstratified meshes use dim instead of depth 8786 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8787 // If any stratum is empty, we must mark all empty 8788 for (d = 0; d <= depth; ++d) { 8789 PetscInt end; 8790 8791 depths[d] = depth - d; 8792 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8793 if (!(starts[d] - end)) empty = PETSC_TRUE; 8794 } 8795 if (empty) 8796 for (d = 0; d <= depth; ++d) { 8797 depths[d] = -1; 8798 starts[d] = -1; 8799 } 8800 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8801 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8802 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]); 8803 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8804 for (d = 0; d <= depth; ++d) { 8805 PetscInt pStart, pEnd, gsize; 8806 8807 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8808 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8809 shift += gsize; 8810 } 8811 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8812 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8813 PetscFunctionReturn(PETSC_SUCCESS); 8814 } 8815 8816 /*@ 8817 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8818 8819 Input Parameter: 8820 . dm - The `DMPLEX` object 8821 8822 Output Parameter: 8823 . ranks - The rank field 8824 8825 Options Database Key: 8826 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8827 8828 Level: intermediate 8829 8830 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8831 @*/ 8832 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8833 { 8834 DM rdm; 8835 PetscFE fe; 8836 PetscScalar *r; 8837 PetscMPIInt rank; 8838 DMPolytopeType ct; 8839 PetscInt dim, cStart, cEnd, c; 8840 PetscBool simplex; 8841 8842 PetscFunctionBeginUser; 8843 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8844 PetscAssertPointer(ranks, 2); 8845 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8846 PetscCall(DMClone(dm, &rdm)); 8847 PetscCall(DMGetDimension(rdm, &dim)); 8848 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8849 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8850 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8851 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8852 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8853 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8854 PetscCall(PetscFEDestroy(&fe)); 8855 PetscCall(DMCreateDS(rdm)); 8856 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8857 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8858 PetscCall(VecGetArray(*ranks, &r)); 8859 for (c = cStart; c < cEnd; ++c) { 8860 PetscScalar *lr; 8861 8862 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8863 if (lr) *lr = rank; 8864 } 8865 PetscCall(VecRestoreArray(*ranks, &r)); 8866 PetscCall(DMDestroy(&rdm)); 8867 PetscFunctionReturn(PETSC_SUCCESS); 8868 } 8869 8870 /*@ 8871 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8872 8873 Input Parameters: 8874 + dm - The `DMPLEX` 8875 - label - The `DMLabel` 8876 8877 Output Parameter: 8878 . val - The label value field 8879 8880 Options Database Key: 8881 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8882 8883 Level: intermediate 8884 8885 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8886 @*/ 8887 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8888 { 8889 DM rdm, plex; 8890 Vec lval; 8891 PetscSection section; 8892 PetscFE fe; 8893 PetscScalar *v; 8894 PetscInt dim, pStart, pEnd, p, cStart; 8895 DMPolytopeType ct; 8896 char name[PETSC_MAX_PATH_LEN]; 8897 const char *lname, *prefix; 8898 8899 PetscFunctionBeginUser; 8900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8901 PetscAssertPointer(label, 2); 8902 PetscAssertPointer(val, 3); 8903 PetscCall(DMClone(dm, &rdm)); 8904 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8905 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8906 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8907 PetscCall(DMDestroy(&plex)); 8908 PetscCall(DMGetDimension(rdm, &dim)); 8909 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8910 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8911 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8912 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8913 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8914 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8915 PetscCall(PetscFEDestroy(&fe)); 8916 PetscCall(DMCreateDS(rdm)); 8917 PetscCall(DMCreateGlobalVector(rdm, val)); 8918 PetscCall(DMCreateLocalVector(rdm, &lval)); 8919 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8920 PetscCall(DMGetLocalSection(rdm, §ion)); 8921 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8922 PetscCall(VecGetArray(lval, &v)); 8923 for (p = pStart; p < pEnd; ++p) { 8924 PetscInt cval, dof, off; 8925 8926 PetscCall(PetscSectionGetDof(section, p, &dof)); 8927 if (!dof) continue; 8928 PetscCall(DMLabelGetValue(label, p, &cval)); 8929 PetscCall(PetscSectionGetOffset(section, p, &off)); 8930 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 8931 } 8932 PetscCall(VecRestoreArray(lval, &v)); 8933 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 8934 PetscCall(VecDestroy(&lval)); 8935 PetscCall(DMDestroy(&rdm)); 8936 PetscFunctionReturn(PETSC_SUCCESS); 8937 } 8938 8939 /*@ 8940 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8941 8942 Input Parameter: 8943 . dm - The `DMPLEX` object 8944 8945 Level: developer 8946 8947 Notes: 8948 This is a useful diagnostic when creating meshes programmatically. 8949 8950 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8951 8952 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8953 @*/ 8954 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8955 { 8956 PetscSection coneSection, supportSection; 8957 const PetscInt *cone, *support; 8958 PetscInt coneSize, c, supportSize, s; 8959 PetscInt pStart, pEnd, p, pp, csize, ssize; 8960 PetscBool storagecheck = PETSC_TRUE; 8961 8962 PetscFunctionBegin; 8963 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8964 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8965 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8966 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8967 /* Check that point p is found in the support of its cone points, and vice versa */ 8968 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8969 for (p = pStart; p < pEnd; ++p) { 8970 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8971 PetscCall(DMPlexGetCone(dm, p, &cone)); 8972 for (c = 0; c < coneSize; ++c) { 8973 PetscBool dup = PETSC_FALSE; 8974 PetscInt d; 8975 for (d = c - 1; d >= 0; --d) { 8976 if (cone[c] == cone[d]) { 8977 dup = PETSC_TRUE; 8978 break; 8979 } 8980 } 8981 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8982 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8983 for (s = 0; s < supportSize; ++s) { 8984 if (support[s] == p) break; 8985 } 8986 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8987 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8988 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8989 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8990 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8991 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8992 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8993 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]); 8994 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8995 } 8996 } 8997 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8998 if (p != pp) { 8999 storagecheck = PETSC_FALSE; 9000 continue; 9001 } 9002 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9003 PetscCall(DMPlexGetSupport(dm, p, &support)); 9004 for (s = 0; s < supportSize; ++s) { 9005 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9006 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9007 for (c = 0; c < coneSize; ++c) { 9008 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9009 if (cone[c] != pp) { 9010 c = 0; 9011 break; 9012 } 9013 if (cone[c] == p) break; 9014 } 9015 if (c >= coneSize) { 9016 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9017 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9018 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9019 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9020 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9021 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9022 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9023 } 9024 } 9025 } 9026 if (storagecheck) { 9027 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9028 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9029 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9030 } 9031 PetscFunctionReturn(PETSC_SUCCESS); 9032 } 9033 9034 /* 9035 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. 9036 */ 9037 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9038 { 9039 DMPolytopeType cct; 9040 PetscInt ptpoints[4]; 9041 const PetscInt *cone, *ccone, *ptcone; 9042 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9043 9044 PetscFunctionBegin; 9045 *unsplit = 0; 9046 switch (ct) { 9047 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9048 ptpoints[npt++] = c; 9049 break; 9050 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9051 PetscCall(DMPlexGetCone(dm, c, &cone)); 9052 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9053 for (cp = 0; cp < coneSize; ++cp) { 9054 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9055 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9056 } 9057 break; 9058 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9059 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9060 PetscCall(DMPlexGetCone(dm, c, &cone)); 9061 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9062 for (cp = 0; cp < coneSize; ++cp) { 9063 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9064 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9065 for (ccp = 0; ccp < cconeSize; ++ccp) { 9066 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9067 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9068 PetscInt p; 9069 for (p = 0; p < npt; ++p) 9070 if (ptpoints[p] == ccone[ccp]) break; 9071 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9072 } 9073 } 9074 } 9075 break; 9076 default: 9077 break; 9078 } 9079 for (pt = 0; pt < npt; ++pt) { 9080 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9081 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9082 } 9083 PetscFunctionReturn(PETSC_SUCCESS); 9084 } 9085 9086 /*@ 9087 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9088 9089 Input Parameters: 9090 + dm - The `DMPLEX` object 9091 - cellHeight - Normally 0 9092 9093 Level: developer 9094 9095 Notes: 9096 This is a useful diagnostic when creating meshes programmatically. 9097 Currently applicable only to homogeneous simplex or tensor meshes. 9098 9099 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9100 9101 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9102 @*/ 9103 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9104 { 9105 DMPlexInterpolatedFlag interp; 9106 DMPolytopeType ct; 9107 PetscInt vStart, vEnd, cStart, cEnd, c; 9108 9109 PetscFunctionBegin; 9110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9111 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9112 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9113 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9114 for (c = cStart; c < cEnd; ++c) { 9115 PetscInt *closure = NULL; 9116 PetscInt coneSize, closureSize, cl, Nv = 0; 9117 9118 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9119 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9120 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9121 if (interp == DMPLEX_INTERPOLATED_FULL) { 9122 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9123 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)); 9124 } 9125 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9126 for (cl = 0; cl < closureSize * 2; cl += 2) { 9127 const PetscInt p = closure[cl]; 9128 if ((p >= vStart) && (p < vEnd)) ++Nv; 9129 } 9130 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9131 /* Special Case: Tensor faces with identified vertices */ 9132 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9133 PetscInt unsplit; 9134 9135 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9136 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9137 } 9138 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)); 9139 } 9140 PetscFunctionReturn(PETSC_SUCCESS); 9141 } 9142 9143 /*@ 9144 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9145 9146 Collective 9147 9148 Input Parameters: 9149 + dm - The `DMPLEX` object 9150 - cellHeight - Normally 0 9151 9152 Level: developer 9153 9154 Notes: 9155 This is a useful diagnostic when creating meshes programmatically. 9156 This routine is only relevant for meshes that are fully interpolated across all ranks. 9157 It will error out if a partially interpolated mesh is given on some rank. 9158 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9159 9160 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9161 9162 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9163 @*/ 9164 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9165 { 9166 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9167 DMPlexInterpolatedFlag interpEnum; 9168 9169 PetscFunctionBegin; 9170 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9171 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9172 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9173 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9174 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9175 PetscFunctionReturn(PETSC_SUCCESS); 9176 } 9177 9178 PetscCall(DMGetDimension(dm, &dim)); 9179 PetscCall(DMPlexGetDepth(dm, &depth)); 9180 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9181 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9182 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9183 for (c = cStart; c < cEnd; ++c) { 9184 const PetscInt *cone, *ornt, *faceSizes, *faces; 9185 const DMPolytopeType *faceTypes; 9186 DMPolytopeType ct; 9187 PetscInt numFaces, coneSize, f; 9188 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9189 9190 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9191 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9192 if (unsplit) continue; 9193 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9194 PetscCall(DMPlexGetCone(dm, c, &cone)); 9195 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9196 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9197 for (cl = 0; cl < closureSize * 2; cl += 2) { 9198 const PetscInt p = closure[cl]; 9199 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9200 } 9201 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9202 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); 9203 for (f = 0; f < numFaces; ++f) { 9204 DMPolytopeType fct; 9205 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9206 9207 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9208 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9209 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9210 const PetscInt p = fclosure[cl]; 9211 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9212 } 9213 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]); 9214 for (v = 0; v < fnumCorners; ++v) { 9215 if (fclosure[v] != faces[fOff + v]) { 9216 PetscInt v1; 9217 9218 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9219 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9220 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9221 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9222 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9223 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]); 9224 } 9225 } 9226 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9227 fOff += faceSizes[f]; 9228 } 9229 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9230 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9231 } 9232 } 9233 PetscFunctionReturn(PETSC_SUCCESS); 9234 } 9235 9236 /*@ 9237 DMPlexCheckGeometry - Check the geometry of mesh cells 9238 9239 Input Parameter: 9240 . dm - The `DMPLEX` object 9241 9242 Level: developer 9243 9244 Notes: 9245 This is a useful diagnostic when creating meshes programmatically. 9246 9247 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9248 9249 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9250 @*/ 9251 PetscErrorCode DMPlexCheckGeometry(DM dm) 9252 { 9253 Vec coordinates; 9254 PetscReal detJ, J[9], refVol = 1.0; 9255 PetscReal vol; 9256 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9257 9258 PetscFunctionBegin; 9259 PetscCall(DMGetDimension(dm, &dim)); 9260 PetscCall(DMGetCoordinateDim(dm, &dE)); 9261 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9262 PetscCall(DMPlexGetDepth(dm, &depth)); 9263 for (d = 0; d < dim; ++d) refVol *= 2.0; 9264 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9265 /* Make sure local coordinates are created, because that step is collective */ 9266 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9267 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9268 for (c = cStart; c < cEnd; ++c) { 9269 DMPolytopeType ct; 9270 PetscInt unsplit; 9271 PetscBool ignoreZeroVol = PETSC_FALSE; 9272 9273 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9274 switch (ct) { 9275 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9276 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9277 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9278 ignoreZeroVol = PETSC_TRUE; 9279 break; 9280 default: 9281 break; 9282 } 9283 switch (ct) { 9284 case DM_POLYTOPE_TRI_PRISM: 9285 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9286 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9287 case DM_POLYTOPE_PYRAMID: 9288 continue; 9289 default: 9290 break; 9291 } 9292 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9293 if (unsplit) continue; 9294 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9295 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); 9296 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9297 /* This should work with periodicity since DG coordinates should be used */ 9298 if (depth > 1) { 9299 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9300 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); 9301 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9302 } 9303 } 9304 PetscFunctionReturn(PETSC_SUCCESS); 9305 } 9306 9307 /*@ 9308 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9309 9310 Collective 9311 9312 Input Parameters: 9313 + dm - The `DMPLEX` object 9314 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9315 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9316 9317 Level: developer 9318 9319 Notes: 9320 This is mainly intended for debugging/testing purposes. 9321 9322 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9323 9324 Extra roots can come from periodic cuts, where additional points appear on the boundary 9325 9326 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9327 @*/ 9328 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9329 { 9330 PetscInt l, nleaves, nroots, overlap; 9331 const PetscInt *locals; 9332 const PetscSFNode *remotes; 9333 PetscBool distributed; 9334 MPI_Comm comm; 9335 PetscMPIInt rank; 9336 9337 PetscFunctionBegin; 9338 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9339 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9340 else pointSF = dm->sf; 9341 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9342 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9343 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9344 { 9345 PetscMPIInt mpiFlag; 9346 9347 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9348 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9349 } 9350 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9351 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9352 if (!distributed) { 9353 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); 9354 PetscFunctionReturn(PETSC_SUCCESS); 9355 } 9356 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); 9357 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9358 9359 /* Check SF graph is compatible with DMPlex chart */ 9360 { 9361 PetscInt pStart, pEnd, maxLeaf; 9362 9363 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9364 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9365 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9366 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9367 } 9368 9369 /* Check Point SF has no local points referenced */ 9370 for (l = 0; l < nleaves; l++) { 9371 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); 9372 } 9373 9374 /* Check there are no cells in interface */ 9375 if (!overlap) { 9376 PetscInt cellHeight, cStart, cEnd; 9377 9378 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9379 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9380 for (l = 0; l < nleaves; ++l) { 9381 const PetscInt point = locals ? locals[l] : l; 9382 9383 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9384 } 9385 } 9386 9387 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9388 { 9389 const PetscInt *rootdegree; 9390 9391 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9392 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9393 for (l = 0; l < nleaves; ++l) { 9394 const PetscInt point = locals ? locals[l] : l; 9395 const PetscInt *cone; 9396 PetscInt coneSize, c, idx; 9397 9398 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9399 PetscCall(DMPlexGetCone(dm, point, &cone)); 9400 for (c = 0; c < coneSize; ++c) { 9401 if (!rootdegree[cone[c]]) { 9402 if (locals) { 9403 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9404 } else { 9405 idx = (cone[c] < nleaves) ? cone[c] : -1; 9406 } 9407 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9408 } 9409 } 9410 } 9411 } 9412 PetscFunctionReturn(PETSC_SUCCESS); 9413 } 9414 9415 /*@ 9416 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9417 9418 Input Parameter: 9419 . dm - The `DMPLEX` object 9420 9421 Level: developer 9422 9423 Notes: 9424 This is a useful diagnostic when creating meshes programmatically. 9425 9426 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9427 9428 Currently does not include `DMPlexCheckCellShape()`. 9429 9430 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9431 @*/ 9432 PetscErrorCode DMPlexCheck(DM dm) 9433 { 9434 PetscInt cellHeight; 9435 9436 PetscFunctionBegin; 9437 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9438 PetscCall(DMPlexCheckSymmetry(dm)); 9439 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9440 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9441 PetscCall(DMPlexCheckGeometry(dm)); 9442 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9443 PetscCall(DMPlexCheckInterfaceCones(dm)); 9444 PetscFunctionReturn(PETSC_SUCCESS); 9445 } 9446 9447 typedef struct cell_stats { 9448 PetscReal min, max, sum, squaresum; 9449 PetscInt count; 9450 } cell_stats_t; 9451 9452 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9453 { 9454 PetscInt i, N = *len; 9455 9456 for (i = 0; i < N; i++) { 9457 cell_stats_t *A = (cell_stats_t *)a; 9458 cell_stats_t *B = (cell_stats_t *)b; 9459 9460 B->min = PetscMin(A->min, B->min); 9461 B->max = PetscMax(A->max, B->max); 9462 B->sum += A->sum; 9463 B->squaresum += A->squaresum; 9464 B->count += A->count; 9465 } 9466 } 9467 9468 /*@ 9469 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9470 9471 Collective 9472 9473 Input Parameters: 9474 + dm - The `DMPLEX` object 9475 . output - If true, statistics will be displayed on `stdout` 9476 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9477 9478 Level: developer 9479 9480 Notes: 9481 This is mainly intended for debugging/testing purposes. 9482 9483 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9484 9485 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9486 @*/ 9487 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9488 { 9489 DM dmCoarse; 9490 cell_stats_t stats, globalStats; 9491 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9492 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9493 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9494 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9495 PetscMPIInt rank, size; 9496 9497 PetscFunctionBegin; 9498 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9499 stats.min = PETSC_MAX_REAL; 9500 stats.max = PETSC_MIN_REAL; 9501 stats.sum = stats.squaresum = 0.; 9502 stats.count = 0; 9503 9504 PetscCallMPI(MPI_Comm_size(comm, &size)); 9505 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9506 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9507 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9508 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9509 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9510 for (c = cStart; c < cEnd; c++) { 9511 PetscInt i; 9512 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9513 9514 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9515 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9516 for (i = 0; i < PetscSqr(cdim); ++i) { 9517 frobJ += J[i] * J[i]; 9518 frobInvJ += invJ[i] * invJ[i]; 9519 } 9520 cond2 = frobJ * frobInvJ; 9521 cond = PetscSqrtReal(cond2); 9522 9523 stats.min = PetscMin(stats.min, cond); 9524 stats.max = PetscMax(stats.max, cond); 9525 stats.sum += cond; 9526 stats.squaresum += cond2; 9527 stats.count++; 9528 if (output && cond > limit) { 9529 PetscSection coordSection; 9530 Vec coordsLocal; 9531 PetscScalar *coords = NULL; 9532 PetscInt Nv, d, clSize, cl, *closure = NULL; 9533 9534 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9535 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9536 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9537 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9538 for (i = 0; i < Nv / cdim; ++i) { 9539 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9540 for (d = 0; d < cdim; ++d) { 9541 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9542 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9543 } 9544 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9545 } 9546 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9547 for (cl = 0; cl < clSize * 2; cl += 2) { 9548 const PetscInt edge = closure[cl]; 9549 9550 if ((edge >= eStart) && (edge < eEnd)) { 9551 PetscReal len; 9552 9553 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9554 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9555 } 9556 } 9557 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9558 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9559 } 9560 } 9561 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9562 9563 if (size > 1) { 9564 PetscMPIInt blockLengths[2] = {4, 1}; 9565 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9566 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9567 MPI_Op statReduce; 9568 9569 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9570 PetscCallMPI(MPI_Type_commit(&statType)); 9571 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9572 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9573 PetscCallMPI(MPI_Op_free(&statReduce)); 9574 PetscCallMPI(MPI_Type_free(&statType)); 9575 } else { 9576 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9577 } 9578 if (rank == 0) { 9579 count = globalStats.count; 9580 min = globalStats.min; 9581 max = globalStats.max; 9582 mean = globalStats.sum / globalStats.count; 9583 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9584 } 9585 9586 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)); 9587 PetscCall(PetscFree2(J, invJ)); 9588 9589 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9590 if (dmCoarse) { 9591 PetscBool isplex; 9592 9593 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9594 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9595 } 9596 PetscFunctionReturn(PETSC_SUCCESS); 9597 } 9598 9599 /*@ 9600 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9601 orthogonal quality below given tolerance. 9602 9603 Collective 9604 9605 Input Parameters: 9606 + dm - The `DMPLEX` object 9607 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9608 - atol - [0, 1] Absolute tolerance for tagging cells. 9609 9610 Output Parameters: 9611 + OrthQual - `Vec` containing orthogonal quality per cell 9612 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9613 9614 Options Database Keys: 9615 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9616 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9617 9618 Level: intermediate 9619 9620 Notes: 9621 Orthogonal quality is given by the following formula\: 9622 9623 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9624 9625 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 9626 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9627 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9628 calculating the cosine of the angle between these vectors. 9629 9630 Orthogonal quality ranges from 1 (best) to 0 (worst). 9631 9632 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9633 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9634 9635 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9636 9637 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9638 @*/ 9639 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9640 { 9641 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9642 PetscInt *idx; 9643 PetscScalar *oqVals; 9644 const PetscScalar *cellGeomArr, *faceGeomArr; 9645 PetscReal *ci, *fi, *Ai; 9646 MPI_Comm comm; 9647 Vec cellgeom, facegeom; 9648 DM dmFace, dmCell; 9649 IS glob; 9650 ISLocalToGlobalMapping ltog; 9651 PetscViewer vwr; 9652 9653 PetscFunctionBegin; 9654 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9655 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9656 PetscAssertPointer(OrthQual, 4); 9657 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9658 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9659 PetscCall(DMGetDimension(dm, &nc)); 9660 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9661 { 9662 DMPlexInterpolatedFlag interpFlag; 9663 9664 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9665 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9666 PetscMPIInt rank; 9667 9668 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9669 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9670 } 9671 } 9672 if (OrthQualLabel) { 9673 PetscAssertPointer(OrthQualLabel, 5); 9674 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9675 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9676 } else { 9677 *OrthQualLabel = NULL; 9678 } 9679 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9680 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9681 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9682 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9683 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9684 PetscCall(VecCreate(comm, OrthQual)); 9685 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9686 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9687 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9688 PetscCall(VecSetUp(*OrthQual)); 9689 PetscCall(ISDestroy(&glob)); 9690 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9691 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9692 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9693 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9694 PetscCall(VecGetDM(cellgeom, &dmCell)); 9695 PetscCall(VecGetDM(facegeom, &dmFace)); 9696 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9697 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9698 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9699 PetscInt cellarr[2], *adj = NULL; 9700 PetscScalar *cArr, *fArr; 9701 PetscReal minvalc = 1.0, minvalf = 1.0; 9702 PetscFVCellGeom *cg; 9703 9704 idx[cellIter] = cell - cStart; 9705 cellarr[0] = cell; 9706 /* Make indexing into cellGeom easier */ 9707 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9708 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9709 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9710 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9711 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9712 PetscInt i; 9713 const PetscInt neigh = adj[cellneigh]; 9714 PetscReal normci = 0, normfi = 0, normai = 0; 9715 PetscFVCellGeom *cgneigh; 9716 PetscFVFaceGeom *fg; 9717 9718 /* Don't count ourselves in the neighbor list */ 9719 if (neigh == cell) continue; 9720 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9721 cellarr[1] = neigh; 9722 { 9723 PetscInt numcovpts; 9724 const PetscInt *covpts; 9725 9726 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9727 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9728 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9729 } 9730 9731 /* Compute c_i, f_i and their norms */ 9732 for (i = 0; i < nc; i++) { 9733 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9734 fi[i] = fg->centroid[i] - cg->centroid[i]; 9735 Ai[i] = fg->normal[i]; 9736 normci += PetscPowReal(ci[i], 2); 9737 normfi += PetscPowReal(fi[i], 2); 9738 normai += PetscPowReal(Ai[i], 2); 9739 } 9740 normci = PetscSqrtReal(normci); 9741 normfi = PetscSqrtReal(normfi); 9742 normai = PetscSqrtReal(normai); 9743 9744 /* Normalize and compute for each face-cell-normal pair */ 9745 for (i = 0; i < nc; i++) { 9746 ci[i] = ci[i] / normci; 9747 fi[i] = fi[i] / normfi; 9748 Ai[i] = Ai[i] / normai; 9749 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9750 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9751 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9752 } 9753 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9754 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9755 } 9756 PetscCall(PetscFree(adj)); 9757 PetscCall(PetscFree2(cArr, fArr)); 9758 /* Defer to cell if they're equal */ 9759 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9760 if (OrthQualLabel) { 9761 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9762 } 9763 } 9764 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9765 PetscCall(VecAssemblyBegin(*OrthQual)); 9766 PetscCall(VecAssemblyEnd(*OrthQual)); 9767 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9768 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9769 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9770 if (OrthQualLabel) { 9771 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9772 } 9773 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9774 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9775 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9776 PetscFunctionReturn(PETSC_SUCCESS); 9777 } 9778 9779 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9780 * interpolator construction */ 9781 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9782 { 9783 PetscSection section, newSection, gsection; 9784 PetscSF sf; 9785 PetscBool hasConstraints, ghasConstraints; 9786 9787 PetscFunctionBegin; 9788 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9789 PetscAssertPointer(odm, 2); 9790 PetscCall(DMGetLocalSection(dm, §ion)); 9791 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9792 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9793 if (!ghasConstraints) { 9794 PetscCall(PetscObjectReference((PetscObject)dm)); 9795 *odm = dm; 9796 PetscFunctionReturn(PETSC_SUCCESS); 9797 } 9798 PetscCall(DMClone(dm, odm)); 9799 PetscCall(DMCopyFields(dm, *odm)); 9800 PetscCall(DMGetLocalSection(*odm, &newSection)); 9801 PetscCall(DMGetPointSF(*odm, &sf)); 9802 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9803 PetscCall(DMSetGlobalSection(*odm, gsection)); 9804 PetscCall(PetscSectionDestroy(&gsection)); 9805 PetscFunctionReturn(PETSC_SUCCESS); 9806 } 9807 9808 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9809 { 9810 DM dmco, dmfo; 9811 Mat interpo; 9812 Vec rscale; 9813 Vec cglobalo, clocal; 9814 Vec fglobal, fglobalo, flocal; 9815 PetscBool regular; 9816 9817 PetscFunctionBegin; 9818 PetscCall(DMGetFullDM(dmc, &dmco)); 9819 PetscCall(DMGetFullDM(dmf, &dmfo)); 9820 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9821 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9822 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9823 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9824 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9825 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9826 PetscCall(VecSet(cglobalo, 0.)); 9827 PetscCall(VecSet(clocal, 0.)); 9828 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9829 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9830 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9831 PetscCall(VecSet(fglobal, 0.)); 9832 PetscCall(VecSet(fglobalo, 0.)); 9833 PetscCall(VecSet(flocal, 0.)); 9834 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9835 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9836 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9837 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9838 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9839 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9840 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9841 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9842 *shift = fglobal; 9843 PetscCall(VecDestroy(&flocal)); 9844 PetscCall(VecDestroy(&fglobalo)); 9845 PetscCall(VecDestroy(&clocal)); 9846 PetscCall(VecDestroy(&cglobalo)); 9847 PetscCall(VecDestroy(&rscale)); 9848 PetscCall(MatDestroy(&interpo)); 9849 PetscCall(DMDestroy(&dmfo)); 9850 PetscCall(DMDestroy(&dmco)); 9851 PetscFunctionReturn(PETSC_SUCCESS); 9852 } 9853 9854 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9855 { 9856 PetscObject shifto; 9857 Vec shift; 9858 9859 PetscFunctionBegin; 9860 if (!interp) { 9861 Vec rscale; 9862 9863 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9864 PetscCall(VecDestroy(&rscale)); 9865 } else { 9866 PetscCall(PetscObjectReference((PetscObject)interp)); 9867 } 9868 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9869 if (!shifto) { 9870 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9871 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9872 shifto = (PetscObject)shift; 9873 PetscCall(VecDestroy(&shift)); 9874 } 9875 shift = (Vec)shifto; 9876 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9877 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9878 PetscCall(MatDestroy(&interp)); 9879 PetscFunctionReturn(PETSC_SUCCESS); 9880 } 9881 9882 /* Pointwise interpolation 9883 Just code FEM for now 9884 u^f = I u^c 9885 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9886 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9887 I_{ij} = psi^f_i phi^c_j 9888 */ 9889 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9890 { 9891 PetscSection gsc, gsf; 9892 PetscInt m, n; 9893 void *ctx; 9894 DM cdm; 9895 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9896 9897 PetscFunctionBegin; 9898 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9899 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9900 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9901 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9902 9903 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9904 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9905 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9906 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9907 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9908 9909 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9910 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9911 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9912 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9913 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9914 if (scaling) { 9915 /* Use naive scaling */ 9916 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9917 } 9918 PetscFunctionReturn(PETSC_SUCCESS); 9919 } 9920 9921 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9922 { 9923 VecScatter ctx; 9924 9925 PetscFunctionBegin; 9926 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9927 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9928 PetscCall(VecScatterDestroy(&ctx)); 9929 PetscFunctionReturn(PETSC_SUCCESS); 9930 } 9931 9932 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[]) 9933 { 9934 const PetscInt Nc = uOff[1] - uOff[0]; 9935 PetscInt c; 9936 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9937 } 9938 9939 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9940 { 9941 DM dmc; 9942 PetscDS ds; 9943 Vec ones, locmass; 9944 IS cellIS; 9945 PetscFormKey key; 9946 PetscInt depth; 9947 9948 PetscFunctionBegin; 9949 PetscCall(DMClone(dm, &dmc)); 9950 PetscCall(DMCopyDisc(dm, dmc)); 9951 PetscCall(DMGetDS(dmc, &ds)); 9952 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9953 PetscCall(DMCreateGlobalVector(dmc, mass)); 9954 PetscCall(DMGetLocalVector(dmc, &ones)); 9955 PetscCall(DMGetLocalVector(dmc, &locmass)); 9956 PetscCall(DMPlexGetDepth(dmc, &depth)); 9957 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9958 PetscCall(VecSet(locmass, 0.0)); 9959 PetscCall(VecSet(ones, 1.0)); 9960 key.label = NULL; 9961 key.value = 0; 9962 key.field = 0; 9963 key.part = 0; 9964 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9965 PetscCall(ISDestroy(&cellIS)); 9966 PetscCall(VecSet(*mass, 0.0)); 9967 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9968 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9969 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9970 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9971 PetscCall(DMDestroy(&dmc)); 9972 PetscFunctionReturn(PETSC_SUCCESS); 9973 } 9974 9975 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9976 { 9977 PetscSection gsc, gsf; 9978 PetscInt m, n; 9979 void *ctx; 9980 DM cdm; 9981 PetscBool regular; 9982 9983 PetscFunctionBegin; 9984 if (dmFine == dmCoarse) { 9985 DM dmc; 9986 PetscDS ds; 9987 PetscWeakForm wf; 9988 Vec u; 9989 IS cellIS; 9990 PetscFormKey key; 9991 PetscInt depth; 9992 9993 PetscCall(DMClone(dmFine, &dmc)); 9994 PetscCall(DMCopyDisc(dmFine, dmc)); 9995 PetscCall(DMGetDS(dmc, &ds)); 9996 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9997 PetscCall(PetscWeakFormClear(wf)); 9998 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9999 PetscCall(DMCreateMatrix(dmc, mass)); 10000 PetscCall(DMGetLocalVector(dmc, &u)); 10001 PetscCall(DMPlexGetDepth(dmc, &depth)); 10002 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10003 PetscCall(MatZeroEntries(*mass)); 10004 key.label = NULL; 10005 key.value = 0; 10006 key.field = 0; 10007 key.part = 0; 10008 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10009 PetscCall(ISDestroy(&cellIS)); 10010 PetscCall(DMRestoreLocalVector(dmc, &u)); 10011 PetscCall(DMDestroy(&dmc)); 10012 } else { 10013 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10014 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10015 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10016 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10017 10018 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10019 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10020 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10021 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10022 10023 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10024 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10025 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10026 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10027 } 10028 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10029 PetscFunctionReturn(PETSC_SUCCESS); 10030 } 10031 10032 /*@ 10033 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10034 10035 Input Parameter: 10036 . dm - The `DMPLEX` object 10037 10038 Output Parameter: 10039 . regular - The flag 10040 10041 Level: intermediate 10042 10043 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10044 @*/ 10045 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10046 { 10047 PetscFunctionBegin; 10048 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10049 PetscAssertPointer(regular, 2); 10050 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10051 PetscFunctionReturn(PETSC_SUCCESS); 10052 } 10053 10054 /*@ 10055 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10056 10057 Input Parameters: 10058 + dm - The `DMPLEX` object 10059 - regular - The flag 10060 10061 Level: intermediate 10062 10063 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10064 @*/ 10065 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10066 { 10067 PetscFunctionBegin; 10068 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10069 ((DM_Plex *)dm->data)->regularRefinement = regular; 10070 PetscFunctionReturn(PETSC_SUCCESS); 10071 } 10072 10073 /*@ 10074 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10075 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10076 10077 Not Collective 10078 10079 Input Parameter: 10080 . dm - The `DMPLEX` object 10081 10082 Output Parameters: 10083 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10084 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10085 10086 Level: intermediate 10087 10088 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10089 @*/ 10090 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10091 { 10092 DM_Plex *plex = (DM_Plex *)dm->data; 10093 10094 PetscFunctionBegin; 10095 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10096 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10097 if (anchorSection) *anchorSection = plex->anchorSection; 10098 if (anchorIS) *anchorIS = plex->anchorIS; 10099 PetscFunctionReturn(PETSC_SUCCESS); 10100 } 10101 10102 /*@ 10103 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10104 10105 Collective 10106 10107 Input Parameters: 10108 + dm - The `DMPLEX` object 10109 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10110 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10111 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10112 10113 Level: intermediate 10114 10115 Notes: 10116 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10117 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10118 combination of other points' degrees of freedom. 10119 10120 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10121 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10122 10123 The reference counts of `anchorSection` and `anchorIS` are incremented. 10124 10125 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10126 @*/ 10127 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10128 { 10129 DM_Plex *plex = (DM_Plex *)dm->data; 10130 PetscMPIInt result; 10131 10132 PetscFunctionBegin; 10133 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10134 if (anchorSection) { 10135 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10136 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10137 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10138 } 10139 if (anchorIS) { 10140 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10141 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10142 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10143 } 10144 10145 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10146 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10147 plex->anchorSection = anchorSection; 10148 10149 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10150 PetscCall(ISDestroy(&plex->anchorIS)); 10151 plex->anchorIS = anchorIS; 10152 10153 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10154 PetscInt size, a, pStart, pEnd; 10155 const PetscInt *anchors; 10156 10157 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10158 PetscCall(ISGetLocalSize(anchorIS, &size)); 10159 PetscCall(ISGetIndices(anchorIS, &anchors)); 10160 for (a = 0; a < size; a++) { 10161 PetscInt p; 10162 10163 p = anchors[a]; 10164 if (p >= pStart && p < pEnd) { 10165 PetscInt dof; 10166 10167 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10168 if (dof) { 10169 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10170 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10171 } 10172 } 10173 } 10174 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10175 } 10176 /* reset the generic constraints */ 10177 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10178 PetscFunctionReturn(PETSC_SUCCESS); 10179 } 10180 10181 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10182 { 10183 PetscSection anchorSection; 10184 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10185 10186 PetscFunctionBegin; 10187 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10188 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10189 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10190 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10191 if (numFields) { 10192 PetscInt f; 10193 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10194 10195 for (f = 0; f < numFields; f++) { 10196 PetscInt numComp; 10197 10198 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10199 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10200 } 10201 } 10202 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10203 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10204 pStart = PetscMax(pStart, sStart); 10205 pEnd = PetscMin(pEnd, sEnd); 10206 pEnd = PetscMax(pStart, pEnd); 10207 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10208 for (p = pStart; p < pEnd; p++) { 10209 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10210 if (dof) { 10211 PetscCall(PetscSectionGetDof(section, p, &dof)); 10212 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10213 for (f = 0; f < numFields; f++) { 10214 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10215 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10216 } 10217 } 10218 } 10219 PetscCall(PetscSectionSetUp(*cSec)); 10220 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10221 PetscFunctionReturn(PETSC_SUCCESS); 10222 } 10223 10224 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10225 { 10226 PetscSection aSec; 10227 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10228 const PetscInt *anchors; 10229 PetscInt numFields, f; 10230 IS aIS; 10231 MatType mtype; 10232 PetscBool iscuda, iskokkos; 10233 10234 PetscFunctionBegin; 10235 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10236 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10237 PetscCall(PetscSectionGetStorageSize(section, &n)); 10238 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10239 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10240 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10241 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10242 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10243 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10244 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10245 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10246 else mtype = MATSEQAIJ; 10247 PetscCall(MatSetType(*cMat, mtype)); 10248 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10249 PetscCall(ISGetIndices(aIS, &anchors)); 10250 /* cSec will be a subset of aSec and section */ 10251 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10252 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10253 PetscCall(PetscMalloc1(m + 1, &i)); 10254 i[0] = 0; 10255 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10256 for (p = pStart; p < pEnd; p++) { 10257 PetscInt rDof, rOff, r; 10258 10259 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10260 if (!rDof) continue; 10261 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10262 if (numFields) { 10263 for (f = 0; f < numFields; f++) { 10264 annz = 0; 10265 for (r = 0; r < rDof; r++) { 10266 a = anchors[rOff + r]; 10267 if (a < sStart || a >= sEnd) continue; 10268 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10269 annz += aDof; 10270 } 10271 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10272 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10273 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10274 } 10275 } else { 10276 annz = 0; 10277 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10278 for (q = 0; q < dof; q++) { 10279 a = anchors[rOff + q]; 10280 if (a < sStart || a >= sEnd) continue; 10281 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10282 annz += aDof; 10283 } 10284 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10285 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10286 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10287 } 10288 } 10289 nnz = i[m]; 10290 PetscCall(PetscMalloc1(nnz, &j)); 10291 offset = 0; 10292 for (p = pStart; p < pEnd; p++) { 10293 if (numFields) { 10294 for (f = 0; f < numFields; f++) { 10295 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10296 for (q = 0; q < dof; q++) { 10297 PetscInt rDof, rOff, r; 10298 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10299 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10300 for (r = 0; r < rDof; r++) { 10301 PetscInt s; 10302 10303 a = anchors[rOff + r]; 10304 if (a < sStart || a >= sEnd) continue; 10305 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10306 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10307 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10308 } 10309 } 10310 } 10311 } else { 10312 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10313 for (q = 0; q < dof; q++) { 10314 PetscInt rDof, rOff, r; 10315 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10316 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10317 for (r = 0; r < rDof; r++) { 10318 PetscInt s; 10319 10320 a = anchors[rOff + r]; 10321 if (a < sStart || a >= sEnd) continue; 10322 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10323 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10324 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10325 } 10326 } 10327 } 10328 } 10329 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10330 PetscCall(PetscFree(i)); 10331 PetscCall(PetscFree(j)); 10332 PetscCall(ISRestoreIndices(aIS, &anchors)); 10333 PetscFunctionReturn(PETSC_SUCCESS); 10334 } 10335 10336 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10337 { 10338 DM_Plex *plex = (DM_Plex *)dm->data; 10339 PetscSection anchorSection, section, cSec; 10340 Mat cMat; 10341 10342 PetscFunctionBegin; 10343 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10344 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10345 if (anchorSection) { 10346 PetscInt Nf; 10347 10348 PetscCall(DMGetLocalSection(dm, §ion)); 10349 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10350 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10351 PetscCall(DMGetNumFields(dm, &Nf)); 10352 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10353 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10354 PetscCall(PetscSectionDestroy(&cSec)); 10355 PetscCall(MatDestroy(&cMat)); 10356 } 10357 PetscFunctionReturn(PETSC_SUCCESS); 10358 } 10359 10360 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10361 { 10362 IS subis; 10363 PetscSection section, subsection; 10364 10365 PetscFunctionBegin; 10366 PetscCall(DMGetLocalSection(dm, §ion)); 10367 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10368 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10369 /* Create subdomain */ 10370 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10371 /* Create submodel */ 10372 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10373 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10374 PetscCall(DMSetLocalSection(*subdm, subsection)); 10375 PetscCall(PetscSectionDestroy(&subsection)); 10376 PetscCall(DMCopyDisc(dm, *subdm)); 10377 /* Create map from submodel to global model */ 10378 if (is) { 10379 PetscSection sectionGlobal, subsectionGlobal; 10380 IS spIS; 10381 const PetscInt *spmap; 10382 PetscInt *subIndices; 10383 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10384 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10385 10386 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10387 PetscCall(ISGetIndices(spIS, &spmap)); 10388 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10389 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10390 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10391 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10392 for (p = pStart; p < pEnd; ++p) { 10393 PetscInt gdof, pSubSize = 0; 10394 10395 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10396 if (gdof > 0) { 10397 for (f = 0; f < Nf; ++f) { 10398 PetscInt fdof, fcdof; 10399 10400 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10401 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10402 pSubSize += fdof - fcdof; 10403 } 10404 subSize += pSubSize; 10405 if (pSubSize) { 10406 if (bs < 0) { 10407 bs = pSubSize; 10408 } else if (bs != pSubSize) { 10409 /* Layout does not admit a pointwise block size */ 10410 bs = 1; 10411 } 10412 } 10413 } 10414 } 10415 /* Must have same blocksize on all procs (some might have no points) */ 10416 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10417 bsLocal[1] = bs; 10418 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10419 if (bsMinMax[0] != bsMinMax[1]) { 10420 bs = 1; 10421 } else { 10422 bs = bsMinMax[0]; 10423 } 10424 PetscCall(PetscMalloc1(subSize, &subIndices)); 10425 for (p = pStart; p < pEnd; ++p) { 10426 PetscInt gdof, goff; 10427 10428 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10429 if (gdof > 0) { 10430 const PetscInt point = spmap[p]; 10431 10432 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10433 for (f = 0; f < Nf; ++f) { 10434 PetscInt fdof, fcdof, fc, f2, poff = 0; 10435 10436 /* Can get rid of this loop by storing field information in the global section */ 10437 for (f2 = 0; f2 < f; ++f2) { 10438 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10439 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10440 poff += fdof - fcdof; 10441 } 10442 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10443 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10444 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10445 } 10446 } 10447 } 10448 PetscCall(ISRestoreIndices(spIS, &spmap)); 10449 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10450 if (bs > 1) { 10451 /* We need to check that the block size does not come from non-contiguous fields */ 10452 PetscInt i, j, set = 1; 10453 for (i = 0; i < subSize; i += bs) { 10454 for (j = 0; j < bs; ++j) { 10455 if (subIndices[i + j] != subIndices[i] + j) { 10456 set = 0; 10457 break; 10458 } 10459 } 10460 } 10461 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10462 } 10463 /* Attach nullspace */ 10464 for (f = 0; f < Nf; ++f) { 10465 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10466 if ((*subdm)->nullspaceConstructors[f]) break; 10467 } 10468 if (f < Nf) { 10469 MatNullSpace nullSpace; 10470 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10471 10472 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10473 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10474 } 10475 } 10476 PetscFunctionReturn(PETSC_SUCCESS); 10477 } 10478 10479 /*@ 10480 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10481 10482 Input Parameters: 10483 + dm - The `DM` 10484 - dummy - unused argument 10485 10486 Options Database Key: 10487 . -dm_plex_monitor_throughput - Activate the monitor 10488 10489 Level: developer 10490 10491 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10492 @*/ 10493 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10494 { 10495 PetscLogHandler default_handler; 10496 10497 PetscFunctionBegin; 10498 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10499 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10500 if (default_handler) { 10501 PetscLogEvent event; 10502 PetscEventPerfInfo eventInfo; 10503 PetscReal cellRate, flopRate; 10504 PetscInt cStart, cEnd, Nf, N; 10505 const char *name; 10506 10507 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10508 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10509 PetscCall(DMGetNumFields(dm, &Nf)); 10510 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10511 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10512 N = (cEnd - cStart) * Nf * eventInfo.count; 10513 flopRate = eventInfo.flops / eventInfo.time; 10514 cellRate = N / eventInfo.time; 10515 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))); 10516 } else { 10517 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."); 10518 } 10519 PetscFunctionReturn(PETSC_SUCCESS); 10520 } 10521