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 PetscBool found = PETSC_FALSE; 89 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 90 91 PetscFunctionBegin; 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 94 PetscCall(ISGetLocalSize(valueIS, &Nct)); 95 PetscCall(ISGetIndices(valueIS, &ctypes)); 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 found = PETSC_TRUE; 114 } 115 if (!Nct || !found) cS = cE = 0; 116 PetscCall(ISDestroy(&valueIS)); 117 // Reset label for fast lookup 118 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 119 if (cStart) *cStart = cS; 120 if (cEnd) *cEnd = cE; 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 125 { 126 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 127 PetscInt *sStart, *sEnd; 128 PetscViewerVTKFieldType *ft; 129 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 130 DMLabel depthLabel, ctLabel; 131 132 PetscFunctionBegin; 133 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 134 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 135 PetscCall(DMGetCoordinateDim(dm, &cdim)); 136 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 137 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 138 if (field >= 0) { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 140 } else { 141 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 142 } 143 144 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 145 PetscCall(DMPlexGetDepth(dm, &depth)); 146 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 147 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 148 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 149 const DMPolytopeType ict = (DMPolytopeType)c; 150 PetscInt dep; 151 152 if (ict == DM_POLYTOPE_FV_GHOST) continue; 153 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 154 if (pStart >= 0) { 155 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 156 if (dep != depth - cellHeight) continue; 157 } 158 if (field >= 0) { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 160 } else { 161 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 162 } 163 } 164 165 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 166 *types = 0; 167 168 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 169 if (globalvcdof[c]) ++(*types); 170 } 171 172 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 173 t = 0; 174 if (globalvcdof[DM_NUM_POLYTOPES]) { 175 sStart[t] = vStart; 176 sEnd[t] = vEnd; 177 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 178 ++t; 179 } 180 181 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 182 if (globalvcdof[c]) { 183 const DMPolytopeType ict = (DMPolytopeType)c; 184 185 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 186 sStart[t] = cStart; 187 sEnd[t] = cEnd; 188 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 189 ++t; 190 } 191 } 192 193 if (!*types) { 194 if (field >= 0) { 195 const char *fieldname; 196 197 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 199 } else { 200 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 201 } 202 } 203 204 *ssStart = sStart; 205 *ssEnd = sEnd; 206 *sft = ft; 207 PetscFunctionReturn(PETSC_SUCCESS); 208 } 209 210 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 211 { 212 PetscFunctionBegin; 213 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 214 PetscFunctionReturn(PETSC_SUCCESS); 215 } 216 217 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 218 { 219 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 220 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 221 222 PetscFunctionBegin; 223 *ft = PETSC_VTK_INVALID; 224 PetscCall(DMGetCoordinateDim(dm, &cdim)); 225 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 226 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 227 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 228 if (field >= 0) { 229 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 230 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 231 } else { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 234 } 235 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 236 if (globalvcdof[0]) { 237 *sStart = vStart; 238 *sEnd = vEnd; 239 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 240 else *ft = PETSC_VTK_POINT_FIELD; 241 } else if (globalvcdof[1]) { 242 *sStart = cStart; 243 *sEnd = cEnd; 244 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 245 else *ft = PETSC_VTK_CELL_FIELD; 246 } else { 247 if (field >= 0) { 248 const char *fieldname; 249 250 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 252 } else { 253 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 254 } 255 } 256 PetscFunctionReturn(PETSC_SUCCESS); 257 } 258 259 /*@ 260 DMPlexVecView1D - Plot many 1D solutions on the same line graph 261 262 Collective 263 264 Input Parameters: 265 + dm - The `DMPLEX` object 266 . n - The number of vectors 267 . u - The array of local vectors 268 - viewer - The `PetscViewer` 269 270 Level: advanced 271 272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 273 @*/ 274 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 275 { 276 PetscDS ds; 277 PetscDraw draw = NULL; 278 PetscDrawLG lg; 279 Vec coordinates; 280 const PetscScalar *coords, **sol; 281 PetscReal *vals; 282 PetscInt *Nc; 283 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 284 char **names; 285 286 PetscFunctionBegin; 287 PetscCall(DMGetDS(dm, &ds)); 288 PetscCall(PetscDSGetNumFields(ds, &Nf)); 289 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 290 PetscCall(PetscDSGetComponents(ds, &Nc)); 291 292 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 293 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 294 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 295 296 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 297 for (i = 0, l = 0; i < n; ++i) { 298 const char *vname; 299 300 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 301 for (f = 0; f < Nf; ++f) { 302 PetscObject disc; 303 const char *fname; 304 char tmpname[PETSC_MAX_PATH_LEN]; 305 306 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 307 /* TODO Create names for components */ 308 for (c = 0; c < Nc[f]; ++c, ++l) { 309 PetscCall(PetscObjectGetName(disc, &fname)); 310 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 312 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 313 PetscCall(PetscStrallocpy(tmpname, &names[l])); 314 } 315 } 316 } 317 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 318 /* Just add P_1 support for now */ 319 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 320 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 321 PetscCall(VecGetArrayRead(coordinates, &coords)); 322 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 323 for (v = vStart; v < vEnd; ++v) { 324 PetscScalar *x, *svals; 325 326 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 327 for (i = 0; i < n; ++i) { 328 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 329 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 330 } 331 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 332 } 333 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 334 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 335 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 336 PetscCall(PetscFree3(sol, names, vals)); 337 338 PetscCall(PetscDrawLGDraw(lg)); 339 PetscCall(PetscDrawLGDestroy(&lg)); 340 PetscFunctionReturn(PETSC_SUCCESS); 341 } 342 343 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 344 { 345 DM dm; 346 347 PetscFunctionBegin; 348 PetscCall(VecGetDM(u, &dm)); 349 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 350 PetscFunctionReturn(PETSC_SUCCESS); 351 } 352 353 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 354 { 355 DM dm; 356 PetscSection s; 357 PetscDraw draw, popup; 358 DM cdm; 359 PetscSection coordSection; 360 Vec coordinates; 361 const PetscScalar *array; 362 PetscReal lbound[3], ubound[3]; 363 PetscReal vbound[2], time; 364 PetscBool flg; 365 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 366 const char *name; 367 char title[PETSC_MAX_PATH_LEN]; 368 369 PetscFunctionBegin; 370 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 371 PetscCall(VecGetDM(v, &dm)); 372 PetscCall(DMGetCoordinateDim(dm, &dim)); 373 PetscCall(DMGetLocalSection(dm, &s)); 374 PetscCall(PetscSectionGetNumFields(s, &Nf)); 375 PetscCall(DMGetCoarsenLevel(dm, &level)); 376 PetscCall(DMGetCoordinateDM(dm, &cdm)); 377 PetscCall(DMGetLocalSection(cdm, &coordSection)); 378 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 379 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 380 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 381 382 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 383 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 384 385 PetscCall(VecGetLocalSize(coordinates, &N)); 386 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 387 PetscCall(PetscDrawClear(draw)); 388 389 /* Could implement something like DMDASelectFields() */ 390 for (f = 0; f < Nf; ++f) { 391 DM fdm = dm; 392 Vec fv = v; 393 IS fis; 394 char prefix[PETSC_MAX_PATH_LEN]; 395 const char *fname; 396 397 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 398 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 399 400 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 401 else prefix[0] = '\0'; 402 if (Nf > 1) { 403 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 404 PetscCall(VecGetSubVector(v, fis, &fv)); 405 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 406 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 407 } 408 for (comp = 0; comp < Nc; ++comp, ++w) { 409 PetscInt nmax = 2; 410 411 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 412 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 413 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 414 PetscCall(PetscDrawSetTitle(draw, title)); 415 416 /* TODO Get max and min only for this component */ 417 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 418 if (!flg) { 419 PetscCall(VecMin(fv, NULL, &vbound[0])); 420 PetscCall(VecMax(fv, NULL, &vbound[1])); 421 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 422 } 423 424 PetscCall(PetscDrawGetPopup(draw, &popup)); 425 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 426 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 427 PetscCall(VecGetArrayRead(fv, &array)); 428 for (c = cStart; c < cEnd; ++c) { 429 PetscScalar *coords = NULL, *a = NULL; 430 const PetscScalar *coords_arr; 431 PetscBool isDG; 432 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 433 434 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 435 if (a) { 436 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 437 color[1] = color[2] = color[3] = color[0]; 438 } else { 439 PetscScalar *vals = NULL; 440 PetscInt numVals, va; 441 442 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 443 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); 444 switch (numVals / Nc) { 445 case 3: /* P1 Triangle */ 446 case 4: /* P1 Quadrangle */ 447 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 448 break; 449 case 6: /* P2 Triangle */ 450 case 8: /* P2 Quadrangle */ 451 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 452 break; 453 default: 454 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 455 } 456 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 457 } 458 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 459 switch (numCoords) { 460 case 6: 461 case 12: /* Localized triangle */ 462 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])); 463 break; 464 case 8: 465 case 16: /* Localized quadrilateral */ 466 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])); 467 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])); 468 break; 469 default: 470 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 471 } 472 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 473 } 474 PetscCall(VecRestoreArrayRead(fv, &array)); 475 PetscCall(PetscDrawFlush(draw)); 476 PetscCall(PetscDrawPause(draw)); 477 PetscCall(PetscDrawSave(draw)); 478 } 479 if (Nf > 1) { 480 PetscCall(VecRestoreSubVector(v, fis, &fv)); 481 PetscCall(ISDestroy(&fis)); 482 PetscCall(DMDestroy(&fdm)); 483 } 484 } 485 PetscFunctionReturn(PETSC_SUCCESS); 486 } 487 488 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 489 { 490 DM dm; 491 PetscDraw draw; 492 PetscInt dim; 493 PetscBool isnull; 494 495 PetscFunctionBegin; 496 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 497 PetscCall(PetscDrawIsNull(draw, &isnull)); 498 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 499 500 PetscCall(VecGetDM(v, &dm)); 501 PetscCall(DMGetCoordinateDim(dm, &dim)); 502 switch (dim) { 503 case 1: 504 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 505 break; 506 case 2: 507 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 508 break; 509 default: 510 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 511 } 512 PetscFunctionReturn(PETSC_SUCCESS); 513 } 514 515 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 516 { 517 DM dm; 518 Vec locv; 519 const char *name; 520 PetscSection section; 521 PetscInt pStart, pEnd; 522 PetscInt numFields; 523 PetscViewerVTKFieldType ft; 524 525 PetscFunctionBegin; 526 PetscCall(VecGetDM(v, &dm)); 527 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 528 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 529 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 530 PetscCall(VecCopy(v, locv)); 531 PetscCall(DMGetLocalSection(dm, §ion)); 532 PetscCall(PetscSectionGetNumFields(section, &numFields)); 533 if (!numFields) { 534 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 535 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 536 } else { 537 PetscInt f; 538 539 for (f = 0; f < numFields; f++) { 540 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 541 if (ft == PETSC_VTK_INVALID) continue; 542 PetscCall(PetscObjectReference((PetscObject)locv)); 543 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 544 } 545 PetscCall(VecDestroy(&locv)); 546 } 547 PetscFunctionReturn(PETSC_SUCCESS); 548 } 549 550 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 551 { 552 DM dm; 553 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 554 555 PetscFunctionBegin; 556 PetscCall(VecGetDM(v, &dm)); 557 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 562 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 563 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 564 PetscInt i, numFields; 565 PetscObject fe; 566 PetscBool fem = PETSC_FALSE; 567 Vec locv = v; 568 const char *name; 569 PetscInt step; 570 PetscReal time; 571 572 PetscCall(DMGetNumFields(dm, &numFields)); 573 for (i = 0; i < numFields; i++) { 574 PetscCall(DMGetField(dm, i, NULL, &fe)); 575 if (fe->classid == PETSCFE_CLASSID) { 576 fem = PETSC_TRUE; 577 break; 578 } 579 } 580 if (fem) { 581 PetscObject isZero; 582 583 PetscCall(DMGetLocalVector(dm, &locv)); 584 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 585 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 586 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 587 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 588 PetscCall(VecCopy(v, locv)); 589 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 590 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 591 } 592 if (isvtk) { 593 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 594 } else if (ishdf5) { 595 #if defined(PETSC_HAVE_HDF5) 596 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 597 #else 598 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 599 #endif 600 } else if (isdraw) { 601 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 602 } else if (isglvis) { 603 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 604 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 605 PetscCall(VecView_GLVis(locv, viewer)); 606 } else if (iscgns) { 607 #if defined(PETSC_HAVE_CGNS) 608 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 609 #else 610 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 611 #endif 612 } 613 if (fem) { 614 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 615 PetscCall(DMRestoreLocalVector(dm, &locv)); 616 } 617 } else { 618 PetscBool isseq; 619 620 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 621 if (isseq) PetscCall(VecView_Seq(v, viewer)); 622 else PetscCall(VecView_MPI(v, viewer)); 623 } 624 PetscFunctionReturn(PETSC_SUCCESS); 625 } 626 627 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 641 if (isvtk || isdraw || isglvis || iscgns) { 642 Vec locv; 643 PetscObject isZero; 644 const char *name; 645 646 PetscCall(DMGetLocalVector(dm, &locv)); 647 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 648 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 649 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 650 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 651 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 652 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 653 PetscCall(VecView_Plex_Local(locv, viewer)); 654 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 655 PetscCall(DMRestoreLocalVector(dm, &locv)); 656 } else if (ishdf5) { 657 #if defined(PETSC_HAVE_HDF5) 658 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 659 #else 660 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 661 #endif 662 } else if (isexodusii) { 663 #if defined(PETSC_HAVE_EXODUSII) 664 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 665 #else 666 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 667 #endif 668 } else { 669 PetscBool isseq; 670 671 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 672 if (isseq) PetscCall(VecView_Seq(v, viewer)); 673 else PetscCall(VecView_MPI(v, viewer)); 674 } 675 PetscFunctionReturn(PETSC_SUCCESS); 676 } 677 678 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 679 { 680 DM dm; 681 MPI_Comm comm; 682 PetscViewerFormat format; 683 Vec v; 684 PetscBool isvtk, ishdf5; 685 686 PetscFunctionBegin; 687 PetscCall(VecGetDM(originalv, &dm)); 688 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 689 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 690 PetscCall(PetscViewerGetFormat(viewer, &format)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 692 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 693 if (format == PETSC_VIEWER_NATIVE) { 694 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 695 /* this need a better fix */ 696 if (dm->useNatural) { 697 if (dm->sfNatural) { 698 const char *vecname; 699 PetscInt n, nroots; 700 701 PetscCall(VecGetLocalSize(originalv, &n)); 702 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 703 if (n == nroots) { 704 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 705 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 706 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 707 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 708 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 709 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 710 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 711 } else v = originalv; 712 } else v = originalv; 713 714 if (ishdf5) { 715 #if defined(PETSC_HAVE_HDF5) 716 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 717 #else 718 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 719 #endif 720 } else if (isvtk) { 721 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 722 } else { 723 PetscBool isseq; 724 725 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 726 if (isseq) PetscCall(VecView_Seq(v, viewer)); 727 else PetscCall(VecView_MPI(v, viewer)); 728 } 729 if (v != originalv) PetscCall(VecDestroy(&v)); 730 PetscFunctionReturn(PETSC_SUCCESS); 731 } 732 733 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 734 { 735 DM dm; 736 PetscBool ishdf5; 737 738 PetscFunctionBegin; 739 PetscCall(VecGetDM(v, &dm)); 740 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 741 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 742 if (ishdf5) { 743 DM dmBC; 744 Vec gv; 745 const char *name; 746 747 PetscCall(DMGetOutputDM(dm, &dmBC)); 748 PetscCall(DMGetGlobalVector(dmBC, &gv)); 749 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 750 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 751 PetscCall(VecLoad_Default(gv, viewer)); 752 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 753 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 754 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 755 } else PetscCall(VecLoad_Default(v, viewer)); 756 PetscFunctionReturn(PETSC_SUCCESS); 757 } 758 759 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 760 { 761 DM dm; 762 PetscBool ishdf5, isexodusii; 763 764 PetscFunctionBegin; 765 PetscCall(VecGetDM(v, &dm)); 766 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 768 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 769 if (ishdf5) { 770 #if defined(PETSC_HAVE_HDF5) 771 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 772 #else 773 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 774 #endif 775 } else if (isexodusii) { 776 #if defined(PETSC_HAVE_EXODUSII) 777 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 778 #else 779 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 780 #endif 781 } else PetscCall(VecLoad_Default(v, viewer)); 782 PetscFunctionReturn(PETSC_SUCCESS); 783 } 784 785 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 786 { 787 DM dm; 788 PetscViewerFormat format; 789 PetscBool ishdf5; 790 791 PetscFunctionBegin; 792 PetscCall(VecGetDM(originalv, &dm)); 793 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 794 PetscCall(PetscViewerGetFormat(viewer, &format)); 795 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 796 if (format == PETSC_VIEWER_NATIVE) { 797 if (dm->useNatural) { 798 if (dm->sfNatural) { 799 if (ishdf5) { 800 #if defined(PETSC_HAVE_HDF5) 801 Vec v; 802 const char *vecname; 803 804 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 805 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 806 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 807 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 808 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 809 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 810 PetscCall(VecDestroy(&v)); 811 #else 812 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 813 #endif 814 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 815 } 816 } else PetscCall(VecLoad_Default(originalv, viewer)); 817 } 818 PetscFunctionReturn(PETSC_SUCCESS); 819 } 820 821 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 822 { 823 PetscSection coordSection; 824 Vec coordinates; 825 DMLabel depthLabel, celltypeLabel; 826 const char *name[4]; 827 const PetscScalar *a; 828 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 829 830 PetscFunctionBegin; 831 PetscCall(DMGetDimension(dm, &dim)); 832 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 833 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 834 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 835 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 836 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 837 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 838 PetscCall(VecGetArrayRead(coordinates, &a)); 839 name[0] = "vertex"; 840 name[1] = "edge"; 841 name[dim - 1] = "face"; 842 name[dim] = "cell"; 843 for (c = cStart; c < cEnd; ++c) { 844 PetscInt *closure = NULL; 845 PetscInt closureSize, cl, ct; 846 847 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 848 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 849 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 850 PetscCall(PetscViewerASCIIPushTab(viewer)); 851 for (cl = 0; cl < closureSize * 2; cl += 2) { 852 PetscInt point = closure[cl], depth, dof, off, d, p; 853 854 if ((point < pStart) || (point >= pEnd)) continue; 855 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 856 if (!dof) continue; 857 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 858 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 859 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 860 for (p = 0; p < dof / dim; ++p) { 861 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 862 for (d = 0; d < dim; ++d) { 863 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 864 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 865 } 866 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 867 } 868 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 869 } 870 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 871 PetscCall(PetscViewerASCIIPopTab(viewer)); 872 } 873 PetscCall(VecRestoreArrayRead(coordinates, &a)); 874 PetscFunctionReturn(PETSC_SUCCESS); 875 } 876 877 typedef enum { 878 CS_CARTESIAN, 879 CS_POLAR, 880 CS_CYLINDRICAL, 881 CS_SPHERICAL 882 } CoordSystem; 883 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 884 885 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 886 { 887 PetscInt i; 888 889 PetscFunctionBegin; 890 if (dim > 3) { 891 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 892 } else { 893 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 894 895 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 896 switch (cs) { 897 case CS_CARTESIAN: 898 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 899 break; 900 case CS_POLAR: 901 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 902 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 903 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 904 break; 905 case CS_CYLINDRICAL: 906 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 907 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 908 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 909 trcoords[2] = coords[2]; 910 break; 911 case CS_SPHERICAL: 912 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 913 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 914 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 915 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 916 break; 917 } 918 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 919 } 920 PetscFunctionReturn(PETSC_SUCCESS); 921 } 922 923 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 924 { 925 DM_Plex *mesh = (DM_Plex *)dm->data; 926 DM cdm, cdmCell; 927 PetscSection coordSection, coordSectionCell; 928 Vec coordinates, coordinatesCell; 929 PetscViewerFormat format; 930 931 PetscFunctionBegin; 932 PetscCall(PetscViewerGetFormat(viewer, &format)); 933 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 934 const char *name; 935 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 936 PetscInt pStart, pEnd, p, numLabels, l; 937 PetscMPIInt rank, size; 938 939 PetscCall(DMGetCoordinateDM(dm, &cdm)); 940 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 941 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 942 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 943 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 944 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 945 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 946 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 947 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 948 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 949 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 950 PetscCall(DMGetDimension(dm, &dim)); 951 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 952 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 953 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 954 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 955 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 956 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 957 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 958 for (p = pStart; p < pEnd; ++p) { 959 PetscInt dof, off, s; 960 961 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 962 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 963 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 964 } 965 PetscCall(PetscViewerFlush(viewer)); 966 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 967 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 968 for (p = pStart; p < pEnd; ++p) { 969 PetscInt dof, off, c; 970 971 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 972 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 973 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])); 974 } 975 PetscCall(PetscViewerFlush(viewer)); 976 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 977 if (coordSection && coordinates) { 978 CoordSystem cs = CS_CARTESIAN; 979 const PetscScalar *array, *arrayCell = NULL; 980 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 981 PetscMPIInt rank; 982 const char *name; 983 984 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 985 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 986 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 987 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 988 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 989 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 990 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 991 pStart = PetscMin(pvStart, pcStart); 992 pEnd = PetscMax(pvEnd, pcEnd); 993 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 994 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 995 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 996 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 997 998 PetscCall(VecGetArrayRead(coordinates, &array)); 999 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1000 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1001 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1002 for (p = pStart; p < pEnd; ++p) { 1003 PetscInt dof, off; 1004 1005 if (p >= pvStart && p < pvEnd) { 1006 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1007 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1008 if (dof) { 1009 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1010 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1011 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1012 } 1013 } 1014 if (cdmCell && p >= pcStart && p < pcEnd) { 1015 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1016 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1017 if (dof) { 1018 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1019 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1020 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1021 } 1022 } 1023 } 1024 PetscCall(PetscViewerFlush(viewer)); 1025 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1026 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1027 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1028 } 1029 PetscCall(DMGetNumLabels(dm, &numLabels)); 1030 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1031 for (l = 0; l < numLabels; ++l) { 1032 DMLabel label; 1033 PetscBool isdepth; 1034 const char *name; 1035 1036 PetscCall(DMGetLabelName(dm, l, &name)); 1037 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1038 if (isdepth) continue; 1039 PetscCall(DMGetLabel(dm, name, &label)); 1040 PetscCall(DMLabelView(label, viewer)); 1041 } 1042 if (size > 1) { 1043 PetscSF sf; 1044 1045 PetscCall(DMGetPointSF(dm, &sf)); 1046 PetscCall(PetscSFView(sf, viewer)); 1047 } 1048 if (mesh->periodic.face_sfs) 1049 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1050 PetscCall(PetscViewerFlush(viewer)); 1051 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1052 const char *name, *color; 1053 const char *defcolors[3] = {"gray", "orange", "green"}; 1054 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1055 char lname[PETSC_MAX_PATH_LEN]; 1056 PetscReal scale = 2.0; 1057 PetscReal tikzscale = 1.0; 1058 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1059 double tcoords[3]; 1060 PetscScalar *coords; 1061 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1062 PetscMPIInt rank, size; 1063 char **names, **colors, **lcolors; 1064 PetscBool flg, lflg; 1065 PetscBT wp = NULL; 1066 PetscInt pEnd, pStart; 1067 1068 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1069 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1070 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1071 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1072 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1073 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1074 PetscCall(DMGetDimension(dm, &dim)); 1075 PetscCall(DMPlexGetDepth(dm, &depth)); 1076 PetscCall(DMGetNumLabels(dm, &numLabels)); 1077 numLabels = PetscMax(numLabels, 10); 1078 numColors = 10; 1079 numLColors = 10; 1080 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1081 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1082 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1083 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1084 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1085 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1086 n = 4; 1087 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1088 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1089 n = 4; 1090 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1091 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1093 if (!useLabels) numLabels = 0; 1094 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1095 if (!useColors) { 1096 numColors = 3; 1097 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1098 } 1099 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1100 if (!useColors) { 1101 numLColors = 4; 1102 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1103 } 1104 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1105 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1106 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1107 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1108 if (depth < dim) plotEdges = PETSC_FALSE; 1109 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1110 1111 /* filter points with labelvalue != labeldefaultvalue */ 1112 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1113 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1114 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1115 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1116 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1117 if (lflg) { 1118 DMLabel lbl; 1119 1120 PetscCall(DMGetLabel(dm, lname, &lbl)); 1121 if (lbl) { 1122 PetscInt val, defval; 1123 1124 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1125 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1126 for (c = pStart; c < pEnd; c++) { 1127 PetscInt *closure = NULL; 1128 PetscInt closureSize; 1129 1130 PetscCall(DMLabelGetValue(lbl, c, &val)); 1131 if (val == defval) continue; 1132 1133 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1134 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1135 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1136 } 1137 } 1138 } 1139 1140 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1141 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1142 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1143 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1144 \\documentclass[tikz]{standalone}\n\n\ 1145 \\usepackage{pgflibraryshapes}\n\ 1146 \\usetikzlibrary{backgrounds}\n\ 1147 \\usetikzlibrary{arrows}\n\ 1148 \\begin{document}\n")); 1149 if (size > 1) { 1150 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1151 for (p = 0; p < size; ++p) { 1152 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1153 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1154 } 1155 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1156 } 1157 if (drawHasse) { 1158 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1159 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1171 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1172 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1173 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1174 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1175 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1176 } 1177 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1178 1179 /* Plot vertices */ 1180 PetscCall(VecGetArray(coordinates, &coords)); 1181 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1182 for (v = vStart; v < vEnd; ++v) { 1183 PetscInt off, dof, d; 1184 PetscBool isLabeled = PETSC_FALSE; 1185 1186 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1187 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1188 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1189 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1190 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1191 for (d = 0; d < dof; ++d) { 1192 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1193 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1194 } 1195 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1196 if (dim == 3) { 1197 PetscReal tmp = tcoords[1]; 1198 tcoords[1] = tcoords[2]; 1199 tcoords[2] = -tmp; 1200 } 1201 for (d = 0; d < dof; ++d) { 1202 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1203 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1204 } 1205 if (drawHasse) color = colors[0 % numColors]; 1206 else color = colors[rank % numColors]; 1207 for (l = 0; l < numLabels; ++l) { 1208 PetscInt val; 1209 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1210 if (val >= 0) { 1211 color = lcolors[l % numLColors]; 1212 isLabeled = PETSC_TRUE; 1213 break; 1214 } 1215 } 1216 if (drawNumbers[0]) { 1217 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1218 } else if (drawColors[0]) { 1219 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1220 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1221 } 1222 PetscCall(VecRestoreArray(coordinates, &coords)); 1223 PetscCall(PetscViewerFlush(viewer)); 1224 /* Plot edges */ 1225 if (plotEdges) { 1226 PetscCall(VecGetArray(coordinates, &coords)); 1227 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1228 for (e = eStart; e < eEnd; ++e) { 1229 const PetscInt *cone; 1230 PetscInt coneSize, offA, offB, dof, d; 1231 1232 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1233 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1234 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1235 PetscCall(DMPlexGetCone(dm, e, &cone)); 1236 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1237 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1238 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1239 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1240 for (d = 0; d < dof; ++d) { 1241 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1242 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1243 } 1244 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1245 if (dim == 3) { 1246 PetscReal tmp = tcoords[1]; 1247 tcoords[1] = tcoords[2]; 1248 tcoords[2] = -tmp; 1249 } 1250 for (d = 0; d < dof; ++d) { 1251 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1252 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1253 } 1254 if (drawHasse) color = colors[1 % numColors]; 1255 else color = colors[rank % numColors]; 1256 for (l = 0; l < numLabels; ++l) { 1257 PetscInt val; 1258 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1259 if (val >= 0) { 1260 color = lcolors[l % numLColors]; 1261 break; 1262 } 1263 } 1264 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1265 } 1266 PetscCall(VecRestoreArray(coordinates, &coords)); 1267 PetscCall(PetscViewerFlush(viewer)); 1268 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1269 } 1270 /* Plot cells */ 1271 if (dim == 3 || !drawNumbers[1]) { 1272 for (e = eStart; e < eEnd; ++e) { 1273 const PetscInt *cone; 1274 1275 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1276 color = colors[rank % numColors]; 1277 for (l = 0; l < numLabels; ++l) { 1278 PetscInt val; 1279 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1280 if (val >= 0) { 1281 color = lcolors[l % numLColors]; 1282 break; 1283 } 1284 } 1285 PetscCall(DMPlexGetCone(dm, e, &cone)); 1286 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1287 } 1288 } else { 1289 DMPolytopeType ct; 1290 1291 /* Drawing a 2D polygon */ 1292 for (c = cStart; c < cEnd; ++c) { 1293 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1294 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1295 if (DMPolytopeTypeIsHybrid(ct)) { 1296 const PetscInt *cone; 1297 PetscInt coneSize, e; 1298 1299 PetscCall(DMPlexGetCone(dm, c, &cone)); 1300 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1301 for (e = 0; e < coneSize; ++e) { 1302 const PetscInt *econe; 1303 1304 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1305 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)); 1306 } 1307 } else { 1308 PetscInt *closure = NULL; 1309 PetscInt closureSize, Nv = 0, v; 1310 1311 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1312 for (p = 0; p < closureSize * 2; p += 2) { 1313 const PetscInt point = closure[p]; 1314 1315 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1316 } 1317 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1318 for (v = 0; v <= Nv; ++v) { 1319 const PetscInt vertex = closure[v % Nv]; 1320 1321 if (v > 0) { 1322 if (plotEdges) { 1323 const PetscInt *edge; 1324 PetscInt endpoints[2], ne; 1325 1326 endpoints[0] = closure[v - 1]; 1327 endpoints[1] = vertex; 1328 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1329 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1330 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1331 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1332 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1333 } 1334 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1335 } 1336 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1337 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1338 } 1339 } 1340 } 1341 for (c = cStart; c < cEnd; ++c) { 1342 double ccoords[3] = {0.0, 0.0, 0.0}; 1343 PetscBool isLabeled = PETSC_FALSE; 1344 PetscScalar *cellCoords = NULL; 1345 const PetscScalar *array; 1346 PetscInt numCoords, cdim, d; 1347 PetscBool isDG; 1348 1349 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1350 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1351 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1352 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1353 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1354 for (p = 0; p < numCoords / cdim; ++p) { 1355 for (d = 0; d < cdim; ++d) { 1356 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1357 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1358 } 1359 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1360 if (cdim == 3) { 1361 PetscReal tmp = tcoords[1]; 1362 tcoords[1] = tcoords[2]; 1363 tcoords[2] = -tmp; 1364 } 1365 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1366 } 1367 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1368 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1369 for (d = 0; d < cdim; ++d) { 1370 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1371 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1372 } 1373 if (drawHasse) color = colors[depth % numColors]; 1374 else color = colors[rank % numColors]; 1375 for (l = 0; l < numLabels; ++l) { 1376 PetscInt val; 1377 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1378 if (val >= 0) { 1379 color = lcolors[l % numLColors]; 1380 isLabeled = PETSC_TRUE; 1381 break; 1382 } 1383 } 1384 if (drawNumbers[dim]) { 1385 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1386 } else if (drawColors[dim]) { 1387 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1388 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1389 } 1390 if (drawHasse) { 1391 int height = 0; 1392 1393 color = colors[depth % numColors]; 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1397 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1398 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1399 1400 if (depth > 2) { 1401 color = colors[1 % numColors]; 1402 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1404 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1405 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1406 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1407 } 1408 1409 color = colors[1 % numColors]; 1410 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1411 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1412 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1413 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1414 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1415 1416 color = colors[0 % numColors]; 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1418 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1419 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1420 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1421 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1422 1423 for (p = pStart; p < pEnd; ++p) { 1424 const PetscInt *cone; 1425 PetscInt coneSize, cp; 1426 1427 PetscCall(DMPlexGetCone(dm, p, &cone)); 1428 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1429 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1430 } 1431 } 1432 PetscCall(PetscViewerFlush(viewer)); 1433 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1434 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1435 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1436 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1437 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1438 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1439 PetscCall(PetscFree3(names, colors, lcolors)); 1440 PetscCall(PetscBTDestroy(&wp)); 1441 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1442 Vec cown, acown; 1443 VecScatter sct; 1444 ISLocalToGlobalMapping g2l; 1445 IS gid, acis; 1446 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1447 MPI_Group ggroup, ngroup; 1448 PetscScalar *array, nid; 1449 const PetscInt *idxs; 1450 PetscInt *idxs2, *start, *adjacency, *work; 1451 PetscInt64 lm[3], gm[3]; 1452 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1453 PetscMPIInt d1, d2, rank; 1454 1455 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1456 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1457 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1458 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1459 #endif 1460 if (ncomm != MPI_COMM_NULL) { 1461 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1462 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1463 d1 = 0; 1464 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1465 nid = d2; 1466 PetscCallMPI(MPI_Group_free(&ggroup)); 1467 PetscCallMPI(MPI_Group_free(&ngroup)); 1468 PetscCallMPI(MPI_Comm_free(&ncomm)); 1469 } else nid = 0.0; 1470 1471 /* Get connectivity */ 1472 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1473 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1474 1475 /* filter overlapped local cells */ 1476 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1477 PetscCall(ISGetIndices(gid, &idxs)); 1478 PetscCall(ISGetLocalSize(gid, &cum)); 1479 PetscCall(PetscMalloc1(cum, &idxs2)); 1480 for (c = cStart, cum = 0; c < cEnd; c++) { 1481 if (idxs[c - cStart] < 0) continue; 1482 idxs2[cum++] = idxs[c - cStart]; 1483 } 1484 PetscCall(ISRestoreIndices(gid, &idxs)); 1485 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1486 PetscCall(ISDestroy(&gid)); 1487 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1488 1489 /* support for node-aware cell locality */ 1490 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1491 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1492 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1493 PetscCall(VecGetArray(cown, &array)); 1494 for (c = 0; c < numVertices; c++) array[c] = nid; 1495 PetscCall(VecRestoreArray(cown, &array)); 1496 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1497 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1498 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1499 PetscCall(ISDestroy(&acis)); 1500 PetscCall(VecScatterDestroy(&sct)); 1501 PetscCall(VecDestroy(&cown)); 1502 1503 /* compute edgeCut */ 1504 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1505 PetscCall(PetscMalloc1(cum, &work)); 1506 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1507 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1508 PetscCall(ISDestroy(&gid)); 1509 PetscCall(VecGetArray(acown, &array)); 1510 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1511 PetscInt totl; 1512 1513 totl = start[c + 1] - start[c]; 1514 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1515 for (i = 0; i < totl; i++) { 1516 if (work[i] < 0) { 1517 ect += 1; 1518 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1519 } 1520 } 1521 } 1522 PetscCall(PetscFree(work)); 1523 PetscCall(VecRestoreArray(acown, &array)); 1524 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1525 lm[1] = -numVertices; 1526 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1527 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1528 lm[0] = ect; /* edgeCut */ 1529 lm[1] = ectn; /* node-aware edgeCut */ 1530 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1531 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1532 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1533 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1534 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1535 #else 1536 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1537 #endif 1538 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1539 PetscCall(PetscFree(start)); 1540 PetscCall(PetscFree(adjacency)); 1541 PetscCall(VecDestroy(&acown)); 1542 } else { 1543 const char *name; 1544 PetscInt *sizes, *hybsizes, *ghostsizes; 1545 PetscInt locDepth, depth, cellHeight, dim, d; 1546 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1547 PetscInt numLabels, l, maxSize = 17; 1548 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1549 MPI_Comm comm; 1550 PetscMPIInt size, rank; 1551 1552 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1553 PetscCallMPI(MPI_Comm_size(comm, &size)); 1554 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1555 PetscCall(DMGetDimension(dm, &dim)); 1556 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1557 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1558 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1559 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1560 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1561 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1562 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1563 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1564 gcNum = gcEnd - gcStart; 1565 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1566 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1567 for (d = 0; d <= depth; d++) { 1568 PetscInt Nc[2] = {0, 0}, ict; 1569 1570 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1571 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1572 ict = ct0; 1573 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1574 ct0 = (DMPolytopeType)ict; 1575 for (p = pStart; p < pEnd; ++p) { 1576 DMPolytopeType ct; 1577 1578 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1579 if (ct == ct0) ++Nc[0]; 1580 else ++Nc[1]; 1581 } 1582 if (size < maxSize) { 1583 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1584 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1585 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1586 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1587 for (p = 0; p < size; ++p) { 1588 if (rank == 0) { 1589 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1590 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1591 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1592 } 1593 } 1594 } else { 1595 PetscInt locMinMax[2]; 1596 1597 locMinMax[0] = Nc[0] + Nc[1]; 1598 locMinMax[1] = Nc[0] + Nc[1]; 1599 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1600 locMinMax[0] = Nc[1]; 1601 locMinMax[1] = Nc[1]; 1602 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1603 if (d == depth) { 1604 locMinMax[0] = gcNum; 1605 locMinMax[1] = gcNum; 1606 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1607 } 1608 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1609 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1610 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1611 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1612 } 1613 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1614 } 1615 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1616 { 1617 const PetscReal *maxCell; 1618 const PetscReal *L; 1619 PetscBool localized; 1620 1621 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1622 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1623 if (L || localized) { 1624 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1625 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1626 if (L) { 1627 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1628 for (d = 0; d < dim; ++d) { 1629 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1630 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1631 } 1632 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1633 } 1634 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1635 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1636 } 1637 } 1638 PetscCall(DMGetNumLabels(dm, &numLabels)); 1639 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1640 for (l = 0; l < numLabels; ++l) { 1641 DMLabel label; 1642 const char *name; 1643 PetscInt *values; 1644 PetscInt numValues, v; 1645 1646 PetscCall(DMGetLabelName(dm, l, &name)); 1647 PetscCall(DMGetLabel(dm, name, &label)); 1648 PetscCall(DMLabelGetNumValues(label, &numValues)); 1649 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1650 1651 { // Extract array of DMLabel values so it can be sorted 1652 IS is_values; 1653 const PetscInt *is_values_local = NULL; 1654 1655 PetscCall(DMLabelGetValueIS(label, &is_values)); 1656 PetscCall(ISGetIndices(is_values, &is_values_local)); 1657 PetscCall(PetscMalloc1(numValues, &values)); 1658 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1659 PetscCall(PetscSortInt(numValues, values)); 1660 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1661 PetscCall(ISDestroy(&is_values)); 1662 } 1663 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1664 for (v = 0; v < numValues; ++v) { 1665 PetscInt size; 1666 1667 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1668 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1669 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1670 } 1671 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1672 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1673 PetscCall(PetscFree(values)); 1674 } 1675 { 1676 char **labelNames; 1677 PetscInt Nl = numLabels; 1678 PetscBool flg; 1679 1680 PetscCall(PetscMalloc1(Nl, &labelNames)); 1681 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1682 for (l = 0; l < Nl; ++l) { 1683 DMLabel label; 1684 1685 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1686 if (flg) { 1687 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1688 PetscCall(DMLabelView(label, viewer)); 1689 } 1690 PetscCall(PetscFree(labelNames[l])); 1691 } 1692 PetscCall(PetscFree(labelNames)); 1693 } 1694 /* If no fields are specified, people do not want to see adjacency */ 1695 if (dm->Nf) { 1696 PetscInt f; 1697 1698 for (f = 0; f < dm->Nf; ++f) { 1699 const char *name; 1700 1701 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1702 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1703 PetscCall(PetscViewerASCIIPushTab(viewer)); 1704 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1705 if (dm->fields[f].adjacency[0]) { 1706 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1707 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1708 } else { 1709 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1710 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1711 } 1712 PetscCall(PetscViewerASCIIPopTab(viewer)); 1713 } 1714 } 1715 PetscCall(DMGetCoarseDM(dm, &cdm)); 1716 if (cdm) { 1717 PetscCall(PetscViewerASCIIPushTab(viewer)); 1718 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1719 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1720 PetscCall(PetscViewerASCIIPopTab(viewer)); 1721 } 1722 } 1723 PetscFunctionReturn(PETSC_SUCCESS); 1724 } 1725 1726 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1727 { 1728 DMPolytopeType ct; 1729 PetscMPIInt rank; 1730 PetscInt cdim; 1731 1732 PetscFunctionBegin; 1733 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1734 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1735 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1736 switch (ct) { 1737 case DM_POLYTOPE_SEGMENT: 1738 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1739 switch (cdim) { 1740 case 1: { 1741 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1742 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1743 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1746 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1747 } break; 1748 case 2: { 1749 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1750 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1751 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1752 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1754 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)); 1755 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)); 1756 } break; 1757 default: 1758 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1759 } 1760 break; 1761 case DM_POLYTOPE_TRIANGLE: 1762 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)); 1763 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1764 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1765 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1766 break; 1767 case DM_POLYTOPE_QUADRILATERAL: 1768 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)); 1769 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)); 1770 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1771 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1772 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1773 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1774 break; 1775 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1776 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)); 1777 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)); 1778 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1779 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1780 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1781 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1782 break; 1783 case DM_POLYTOPE_FV_GHOST: 1784 break; 1785 default: 1786 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1787 } 1788 PetscFunctionReturn(PETSC_SUCCESS); 1789 } 1790 1791 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1792 { 1793 PetscReal centroid[2] = {0., 0.}; 1794 PetscMPIInt rank; 1795 PetscInt fillColor; 1796 1797 PetscFunctionBegin; 1798 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1799 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1800 for (PetscInt v = 0; v < Nv; ++v) { 1801 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1802 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1803 } 1804 for (PetscInt e = 0; e < Nv; ++e) { 1805 refCoords[0] = refVertices[e * 2 + 0]; 1806 refCoords[1] = refVertices[e * 2 + 1]; 1807 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1808 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1809 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1810 } 1811 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1812 for (PetscInt d = 0; d < edgeDiv; ++d) { 1813 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)); 1814 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1815 } 1816 } 1817 PetscFunctionReturn(PETSC_SUCCESS); 1818 } 1819 1820 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1821 { 1822 DMPolytopeType ct; 1823 1824 PetscFunctionBegin; 1825 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1826 switch (ct) { 1827 case DM_POLYTOPE_TRIANGLE: { 1828 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1829 1830 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1831 } break; 1832 case DM_POLYTOPE_QUADRILATERAL: { 1833 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1834 1835 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1836 } break; 1837 default: 1838 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1839 } 1840 PetscFunctionReturn(PETSC_SUCCESS); 1841 } 1842 1843 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1844 { 1845 PetscDraw draw; 1846 DM cdm; 1847 PetscSection coordSection; 1848 Vec coordinates; 1849 PetscReal xyl[3], xyr[3]; 1850 PetscReal *refCoords, *edgeCoords; 1851 PetscBool isnull, drawAffine; 1852 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1853 1854 PetscFunctionBegin; 1855 PetscCall(DMGetCoordinateDim(dm, &dim)); 1856 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1857 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1858 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1859 edgeDiv = cDegree + 1; 1860 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1861 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1862 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1863 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1864 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1865 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1866 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1867 1868 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1869 PetscCall(PetscDrawIsNull(draw, &isnull)); 1870 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1871 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1872 1873 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1874 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1875 PetscCall(PetscDrawClear(draw)); 1876 1877 for (c = cStart; c < cEnd; ++c) { 1878 PetscScalar *coords = NULL; 1879 const PetscScalar *coords_arr; 1880 PetscInt numCoords; 1881 PetscBool isDG; 1882 1883 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1884 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1885 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1886 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1887 } 1888 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1889 PetscCall(PetscDrawFlush(draw)); 1890 PetscCall(PetscDrawPause(draw)); 1891 PetscCall(PetscDrawSave(draw)); 1892 PetscFunctionReturn(PETSC_SUCCESS); 1893 } 1894 1895 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1896 { 1897 DM odm = dm, rdm = dm, cdm; 1898 PetscFE fe; 1899 PetscSpace sp; 1900 PetscClassId id; 1901 PetscInt degree; 1902 PetscBool hoView = PETSC_TRUE; 1903 1904 PetscFunctionBegin; 1905 PetscObjectOptionsBegin((PetscObject)dm); 1906 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1907 PetscOptionsEnd(); 1908 PetscCall(PetscObjectReference((PetscObject)dm)); 1909 *hdm = dm; 1910 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1911 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1912 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1913 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1914 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1915 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1916 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1917 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1918 DM cdm, rcdm; 1919 Mat In; 1920 Vec cl, rcl; 1921 1922 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1923 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1924 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1925 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1926 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1927 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1928 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1929 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1930 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1931 PetscCall(MatMult(In, cl, rcl)); 1932 PetscCall(MatDestroy(&In)); 1933 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1934 PetscCall(DMDestroy(&odm)); 1935 odm = rdm; 1936 } 1937 *hdm = rdm; 1938 PetscFunctionReturn(PETSC_SUCCESS); 1939 } 1940 1941 #if defined(PETSC_HAVE_EXODUSII) 1942 #include <exodusII.h> 1943 #include <petscviewerexodusii.h> 1944 #endif 1945 1946 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1947 { 1948 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1949 char name[PETSC_MAX_PATH_LEN]; 1950 1951 PetscFunctionBegin; 1952 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1953 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1954 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1955 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1956 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1957 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1958 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1959 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1960 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1961 if (iascii) { 1962 PetscViewerFormat format; 1963 PetscCall(PetscViewerGetFormat(viewer, &format)); 1964 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1965 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1966 } else if (ishdf5) { 1967 #if defined(PETSC_HAVE_HDF5) 1968 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1969 #else 1970 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1971 #endif 1972 } else if (isvtk) { 1973 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1974 } else if (isdraw) { 1975 DM hdm; 1976 1977 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1978 PetscCall(DMPlexView_Draw(hdm, viewer)); 1979 PetscCall(DMDestroy(&hdm)); 1980 } else if (isglvis) { 1981 PetscCall(DMPlexView_GLVis(dm, viewer)); 1982 #if defined(PETSC_HAVE_EXODUSII) 1983 } else if (isexodus) { 1984 /* 1985 exodusII requires that all sets be part of exactly one cell set. 1986 If the dm does not have a "Cell Sets" label defined, we create one 1987 with ID 1, containing all cells. 1988 Note that if the Cell Sets label is defined but does not cover all cells, 1989 we may still have a problem. This should probably be checked here or in the viewer; 1990 */ 1991 PetscInt numCS; 1992 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1993 if (!numCS) { 1994 PetscInt cStart, cEnd, c; 1995 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1996 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1997 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1998 } 1999 PetscCall(DMView_PlexExodusII(dm, viewer)); 2000 #endif 2001 #if defined(PETSC_HAVE_CGNS) 2002 } else if (iscgns) { 2003 PetscCall(DMView_PlexCGNS(dm, viewer)); 2004 #endif 2005 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2006 /* Optionally view the partition */ 2007 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2008 if (flg) { 2009 Vec ranks; 2010 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2011 PetscCall(VecView(ranks, viewer)); 2012 PetscCall(VecDestroy(&ranks)); 2013 } 2014 /* Optionally view a label */ 2015 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2016 if (flg) { 2017 DMLabel label; 2018 Vec val; 2019 2020 PetscCall(DMGetLabel(dm, name, &label)); 2021 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2022 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2023 PetscCall(VecView(val, viewer)); 2024 PetscCall(VecDestroy(&val)); 2025 } 2026 PetscFunctionReturn(PETSC_SUCCESS); 2027 } 2028 2029 /*@ 2030 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2031 2032 Collective 2033 2034 Input Parameters: 2035 + dm - The `DM` whose topology is to be saved 2036 - viewer - The `PetscViewer` to save it in 2037 2038 Level: advanced 2039 2040 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2041 @*/ 2042 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2043 { 2044 PetscBool ishdf5; 2045 2046 PetscFunctionBegin; 2047 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2048 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2049 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2050 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2051 if (ishdf5) { 2052 #if defined(PETSC_HAVE_HDF5) 2053 PetscViewerFormat format; 2054 PetscCall(PetscViewerGetFormat(viewer, &format)); 2055 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2056 IS globalPointNumbering; 2057 2058 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2059 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2060 PetscCall(ISDestroy(&globalPointNumbering)); 2061 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2062 #else 2063 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2064 #endif 2065 } 2066 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2067 PetscFunctionReturn(PETSC_SUCCESS); 2068 } 2069 2070 /*@ 2071 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2072 2073 Collective 2074 2075 Input Parameters: 2076 + dm - The `DM` whose coordinates are to be saved 2077 - viewer - The `PetscViewer` for saving 2078 2079 Level: advanced 2080 2081 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2082 @*/ 2083 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2084 { 2085 PetscBool ishdf5; 2086 2087 PetscFunctionBegin; 2088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2089 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2090 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2091 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2092 if (ishdf5) { 2093 #if defined(PETSC_HAVE_HDF5) 2094 PetscViewerFormat format; 2095 PetscCall(PetscViewerGetFormat(viewer, &format)); 2096 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2097 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2098 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2099 #else 2100 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2101 #endif 2102 } 2103 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2104 PetscFunctionReturn(PETSC_SUCCESS); 2105 } 2106 2107 /*@ 2108 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2109 2110 Collective 2111 2112 Input Parameters: 2113 + dm - The `DM` whose labels are to be saved 2114 - viewer - The `PetscViewer` for saving 2115 2116 Level: advanced 2117 2118 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2119 @*/ 2120 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2121 { 2122 PetscBool ishdf5; 2123 2124 PetscFunctionBegin; 2125 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2126 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2127 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2128 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2129 if (ishdf5) { 2130 #if defined(PETSC_HAVE_HDF5) 2131 IS globalPointNumbering; 2132 PetscViewerFormat format; 2133 2134 PetscCall(PetscViewerGetFormat(viewer, &format)); 2135 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2136 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2137 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2138 PetscCall(ISDestroy(&globalPointNumbering)); 2139 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2140 #else 2141 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2142 #endif 2143 } 2144 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2145 PetscFunctionReturn(PETSC_SUCCESS); 2146 } 2147 2148 /*@ 2149 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2150 2151 Collective 2152 2153 Input Parameters: 2154 + dm - The `DM` that contains the topology on which the section to be saved is defined 2155 . viewer - The `PetscViewer` for saving 2156 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2157 2158 Level: advanced 2159 2160 Notes: 2161 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. 2162 2163 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. 2164 2165 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2166 @*/ 2167 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2168 { 2169 PetscBool ishdf5; 2170 2171 PetscFunctionBegin; 2172 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2173 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2174 if (!sectiondm) sectiondm = dm; 2175 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2176 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2177 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2178 if (ishdf5) { 2179 #if defined(PETSC_HAVE_HDF5) 2180 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2181 #else 2182 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2183 #endif 2184 } 2185 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2186 PetscFunctionReturn(PETSC_SUCCESS); 2187 } 2188 2189 /*@ 2190 DMPlexGlobalVectorView - Saves a global vector 2191 2192 Collective 2193 2194 Input Parameters: 2195 + dm - The `DM` that represents the topology 2196 . viewer - The `PetscViewer` to save data with 2197 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2198 - vec - The global vector to be saved 2199 2200 Level: advanced 2201 2202 Notes: 2203 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. 2204 2205 Calling sequence: 2206 .vb 2207 DMCreate(PETSC_COMM_WORLD, &dm); 2208 DMSetType(dm, DMPLEX); 2209 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2210 DMClone(dm, §iondm); 2211 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2212 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2213 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2214 PetscSectionSetChart(section, pStart, pEnd); 2215 PetscSectionSetUp(section); 2216 DMSetLocalSection(sectiondm, section); 2217 PetscSectionDestroy(§ion); 2218 DMGetGlobalVector(sectiondm, &vec); 2219 PetscObjectSetName((PetscObject)vec, "vec_name"); 2220 DMPlexTopologyView(dm, viewer); 2221 DMPlexSectionView(dm, viewer, sectiondm); 2222 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2223 DMRestoreGlobalVector(sectiondm, &vec); 2224 DMDestroy(§iondm); 2225 DMDestroy(&dm); 2226 .ve 2227 2228 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2229 @*/ 2230 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2231 { 2232 PetscBool ishdf5; 2233 2234 PetscFunctionBegin; 2235 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2236 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2237 if (!sectiondm) sectiondm = dm; 2238 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2239 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2240 /* Check consistency */ 2241 { 2242 PetscSection section; 2243 PetscBool includesConstraints; 2244 PetscInt m, m1; 2245 2246 PetscCall(VecGetLocalSize(vec, &m1)); 2247 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2248 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2249 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2250 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2251 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2252 } 2253 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2254 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2255 if (ishdf5) { 2256 #if defined(PETSC_HAVE_HDF5) 2257 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2258 #else 2259 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2260 #endif 2261 } 2262 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2263 PetscFunctionReturn(PETSC_SUCCESS); 2264 } 2265 2266 /*@ 2267 DMPlexLocalVectorView - Saves a local vector 2268 2269 Collective 2270 2271 Input Parameters: 2272 + dm - The `DM` that represents the topology 2273 . viewer - The `PetscViewer` to save data with 2274 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2275 - vec - The local vector to be saved 2276 2277 Level: advanced 2278 2279 Note: 2280 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. 2281 2282 Calling sequence: 2283 .vb 2284 DMCreate(PETSC_COMM_WORLD, &dm); 2285 DMSetType(dm, DMPLEX); 2286 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2287 DMClone(dm, §iondm); 2288 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2289 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2290 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2291 PetscSectionSetChart(section, pStart, pEnd); 2292 PetscSectionSetUp(section); 2293 DMSetLocalSection(sectiondm, section); 2294 DMGetLocalVector(sectiondm, &vec); 2295 PetscObjectSetName((PetscObject)vec, "vec_name"); 2296 DMPlexTopologyView(dm, viewer); 2297 DMPlexSectionView(dm, viewer, sectiondm); 2298 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2299 DMRestoreLocalVector(sectiondm, &vec); 2300 DMDestroy(§iondm); 2301 DMDestroy(&dm); 2302 .ve 2303 2304 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2305 @*/ 2306 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2307 { 2308 PetscBool ishdf5; 2309 2310 PetscFunctionBegin; 2311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2312 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2313 if (!sectiondm) sectiondm = dm; 2314 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2315 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2316 /* Check consistency */ 2317 { 2318 PetscSection section; 2319 PetscBool includesConstraints; 2320 PetscInt m, m1; 2321 2322 PetscCall(VecGetLocalSize(vec, &m1)); 2323 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2324 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2325 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2326 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2327 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2328 } 2329 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2330 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2331 if (ishdf5) { 2332 #if defined(PETSC_HAVE_HDF5) 2333 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2334 #else 2335 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2336 #endif 2337 } 2338 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2339 PetscFunctionReturn(PETSC_SUCCESS); 2340 } 2341 2342 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2343 { 2344 PetscBool ishdf5; 2345 2346 PetscFunctionBegin; 2347 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2348 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2349 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2350 if (ishdf5) { 2351 #if defined(PETSC_HAVE_HDF5) 2352 PetscViewerFormat format; 2353 PetscCall(PetscViewerGetFormat(viewer, &format)); 2354 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2355 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2356 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2357 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2358 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2359 PetscFunctionReturn(PETSC_SUCCESS); 2360 #else 2361 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2362 #endif 2363 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2364 } 2365 2366 /*@ 2367 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2368 2369 Collective 2370 2371 Input Parameters: 2372 + dm - The `DM` into which the topology is loaded 2373 - viewer - The `PetscViewer` for the saved topology 2374 2375 Output Parameter: 2376 . 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; 2377 `NULL` if unneeded 2378 2379 Level: advanced 2380 2381 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2382 `PetscViewer`, `PetscSF` 2383 @*/ 2384 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2385 { 2386 PetscBool ishdf5; 2387 2388 PetscFunctionBegin; 2389 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2390 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2391 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2392 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2393 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2394 if (ishdf5) { 2395 #if defined(PETSC_HAVE_HDF5) 2396 PetscViewerFormat format; 2397 PetscCall(PetscViewerGetFormat(viewer, &format)); 2398 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2399 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2400 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2401 #else 2402 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2403 #endif 2404 } 2405 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2406 PetscFunctionReturn(PETSC_SUCCESS); 2407 } 2408 2409 /*@ 2410 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2411 2412 Collective 2413 2414 Input Parameters: 2415 + dm - The `DM` into which the coordinates are loaded 2416 . viewer - The `PetscViewer` for the saved coordinates 2417 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2418 2419 Level: advanced 2420 2421 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2422 `PetscSF`, `PetscViewer` 2423 @*/ 2424 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2425 { 2426 PetscBool ishdf5; 2427 2428 PetscFunctionBegin; 2429 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2430 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2431 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2432 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2433 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2434 if (ishdf5) { 2435 #if defined(PETSC_HAVE_HDF5) 2436 PetscViewerFormat format; 2437 PetscCall(PetscViewerGetFormat(viewer, &format)); 2438 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2439 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2440 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2441 #else 2442 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2443 #endif 2444 } 2445 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2446 PetscFunctionReturn(PETSC_SUCCESS); 2447 } 2448 2449 /*@ 2450 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2451 2452 Collective 2453 2454 Input Parameters: 2455 + dm - The `DM` into which the labels are loaded 2456 . viewer - The `PetscViewer` for the saved labels 2457 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2458 2459 Level: advanced 2460 2461 Note: 2462 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2463 2464 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2465 `PetscSF`, `PetscViewer` 2466 @*/ 2467 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2468 { 2469 PetscBool ishdf5; 2470 2471 PetscFunctionBegin; 2472 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2473 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2474 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2475 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2476 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2477 if (ishdf5) { 2478 #if defined(PETSC_HAVE_HDF5) 2479 PetscViewerFormat format; 2480 2481 PetscCall(PetscViewerGetFormat(viewer, &format)); 2482 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2483 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2484 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2485 #else 2486 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2487 #endif 2488 } 2489 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2490 PetscFunctionReturn(PETSC_SUCCESS); 2491 } 2492 2493 /*@ 2494 DMPlexSectionLoad - Loads section into a `DMPLEX` 2495 2496 Collective 2497 2498 Input Parameters: 2499 + dm - The `DM` that represents the topology 2500 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2501 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2502 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2503 2504 Output Parameters: 2505 + 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) 2506 - 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) 2507 2508 Level: advanced 2509 2510 Notes: 2511 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. 2512 2513 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. 2514 2515 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. 2516 2517 Example using 2 processes: 2518 .vb 2519 NX (number of points on dm): 4 2520 sectionA : the on-disk section 2521 vecA : a vector associated with sectionA 2522 sectionB : sectiondm's local section constructed in this function 2523 vecB (local) : a vector associated with sectiondm's local section 2524 vecB (global) : a vector associated with sectiondm's global section 2525 2526 rank 0 rank 1 2527 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2528 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2529 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2530 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2531 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2532 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2533 sectionB->atlasDof : 1 0 1 | 1 3 2534 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2535 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2536 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2537 .ve 2538 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2539 2540 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2541 @*/ 2542 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2543 { 2544 PetscBool ishdf5; 2545 2546 PetscFunctionBegin; 2547 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2548 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2549 if (!sectiondm) sectiondm = dm; 2550 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2551 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2552 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2553 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2554 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2555 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2556 if (ishdf5) { 2557 #if defined(PETSC_HAVE_HDF5) 2558 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2559 #else 2560 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2561 #endif 2562 } 2563 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2564 PetscFunctionReturn(PETSC_SUCCESS); 2565 } 2566 2567 /*@ 2568 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2569 2570 Collective 2571 2572 Input Parameters: 2573 + dm - The `DM` that represents the topology 2574 . viewer - The `PetscViewer` that represents the on-disk vector data 2575 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2576 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2577 - vec - The global vector to set values of 2578 2579 Level: advanced 2580 2581 Notes: 2582 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. 2583 2584 Calling sequence: 2585 .vb 2586 DMCreate(PETSC_COMM_WORLD, &dm); 2587 DMSetType(dm, DMPLEX); 2588 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2589 DMPlexTopologyLoad(dm, viewer, &sfX); 2590 DMClone(dm, §iondm); 2591 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2592 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2593 DMGetGlobalVector(sectiondm, &vec); 2594 PetscObjectSetName((PetscObject)vec, "vec_name"); 2595 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2596 DMRestoreGlobalVector(sectiondm, &vec); 2597 PetscSFDestroy(&gsf); 2598 PetscSFDestroy(&sfX); 2599 DMDestroy(§iondm); 2600 DMDestroy(&dm); 2601 .ve 2602 2603 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2604 `PetscSF`, `PetscViewer` 2605 @*/ 2606 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2607 { 2608 PetscBool ishdf5; 2609 2610 PetscFunctionBegin; 2611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2612 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2613 if (!sectiondm) sectiondm = dm; 2614 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2615 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2616 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2617 /* Check consistency */ 2618 { 2619 PetscSection section; 2620 PetscBool includesConstraints; 2621 PetscInt m, m1; 2622 2623 PetscCall(VecGetLocalSize(vec, &m1)); 2624 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2625 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2626 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2627 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2628 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2629 } 2630 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2631 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2632 if (ishdf5) { 2633 #if defined(PETSC_HAVE_HDF5) 2634 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2635 #else 2636 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2637 #endif 2638 } 2639 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2640 PetscFunctionReturn(PETSC_SUCCESS); 2641 } 2642 2643 /*@ 2644 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2645 2646 Collective 2647 2648 Input Parameters: 2649 + dm - The `DM` that represents the topology 2650 . viewer - The `PetscViewer` that represents the on-disk vector data 2651 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2652 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2653 - vec - The local vector to set values of 2654 2655 Level: advanced 2656 2657 Notes: 2658 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. 2659 2660 Calling sequence: 2661 .vb 2662 DMCreate(PETSC_COMM_WORLD, &dm); 2663 DMSetType(dm, DMPLEX); 2664 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2665 DMPlexTopologyLoad(dm, viewer, &sfX); 2666 DMClone(dm, §iondm); 2667 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2668 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2669 DMGetLocalVector(sectiondm, &vec); 2670 PetscObjectSetName((PetscObject)vec, "vec_name"); 2671 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2672 DMRestoreLocalVector(sectiondm, &vec); 2673 PetscSFDestroy(&lsf); 2674 PetscSFDestroy(&sfX); 2675 DMDestroy(§iondm); 2676 DMDestroy(&dm); 2677 .ve 2678 2679 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2680 `PetscSF`, `PetscViewer` 2681 @*/ 2682 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2683 { 2684 PetscBool ishdf5; 2685 2686 PetscFunctionBegin; 2687 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2688 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2689 if (!sectiondm) sectiondm = dm; 2690 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2691 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2692 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2693 /* Check consistency */ 2694 { 2695 PetscSection section; 2696 PetscBool includesConstraints; 2697 PetscInt m, m1; 2698 2699 PetscCall(VecGetLocalSize(vec, &m1)); 2700 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2701 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2702 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2703 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2704 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2705 } 2706 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2707 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2708 if (ishdf5) { 2709 #if defined(PETSC_HAVE_HDF5) 2710 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2711 #else 2712 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2713 #endif 2714 } 2715 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2716 PetscFunctionReturn(PETSC_SUCCESS); 2717 } 2718 2719 PetscErrorCode DMDestroy_Plex(DM dm) 2720 { 2721 DM_Plex *mesh = (DM_Plex *)dm->data; 2722 2723 PetscFunctionBegin; 2724 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2725 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2726 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2727 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2728 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2729 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2730 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2731 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2732 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2733 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2734 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2735 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2736 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2737 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2738 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2739 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2740 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2741 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2742 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2743 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2744 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2745 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2746 PetscCall(PetscFree(mesh->cones)); 2747 PetscCall(PetscFree(mesh->coneOrientations)); 2748 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2749 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2750 PetscCall(PetscFree(mesh->supports)); 2751 PetscCall(PetscFree(mesh->cellTypes)); 2752 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2753 PetscCall(PetscFree(mesh->tetgenOpts)); 2754 PetscCall(PetscFree(mesh->triangleOpts)); 2755 PetscCall(PetscFree(mesh->transformType)); 2756 PetscCall(PetscFree(mesh->distributionName)); 2757 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2758 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2759 PetscCall(ISDestroy(&mesh->subpointIS)); 2760 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2761 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2762 if (mesh->periodic.face_sfs) { 2763 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2764 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2765 } 2766 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2767 if (mesh->periodic.periodic_points) { 2768 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2769 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2770 } 2771 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2772 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2773 PetscCall(ISDestroy(&mesh->anchorIS)); 2774 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2775 PetscCall(PetscFree(mesh->parents)); 2776 PetscCall(PetscFree(mesh->childIDs)); 2777 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2778 PetscCall(PetscFree(mesh->children)); 2779 PetscCall(DMDestroy(&mesh->referenceTree)); 2780 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2781 PetscCall(PetscFree(mesh->neighbors)); 2782 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2783 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2784 PetscCall(PetscFree(mesh)); 2785 PetscFunctionReturn(PETSC_SUCCESS); 2786 } 2787 2788 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2789 { 2790 PetscSection sectionGlobal, sectionLocal; 2791 PetscInt bs = -1, mbs; 2792 PetscInt localSize, localStart = 0; 2793 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2794 MatType mtype; 2795 ISLocalToGlobalMapping ltog; 2796 2797 PetscFunctionBegin; 2798 PetscCall(MatInitializePackage()); 2799 mtype = dm->mattype; 2800 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2801 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2802 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2803 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2804 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2805 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2806 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2807 PetscCall(MatSetType(*J, mtype)); 2808 PetscCall(MatSetFromOptions(*J)); 2809 PetscCall(MatGetBlockSize(*J, &mbs)); 2810 if (mbs > 1) bs = mbs; 2811 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2812 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2813 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2814 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2815 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2816 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2817 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2818 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2819 if (!isShell) { 2820 // There are three states with pblocks, since block starts can have no dofs: 2821 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2822 // TRUE) Block Start: The first entry in a block has been added 2823 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2824 PetscBT blst; 2825 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2826 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2827 const PetscInt *perm = NULL; 2828 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2829 PetscInt pStart, pEnd, dof, cdof, num_fields; 2830 2831 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2832 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2833 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2834 2835 PetscCall(PetscCalloc1(localSize, &pblocks)); 2836 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2837 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2838 // We need to process in the permuted order to get block sizes right 2839 for (PetscInt point = pStart; point < pEnd; ++point) { 2840 const PetscInt p = perm ? perm[point] : point; 2841 2842 switch (dm->blocking_type) { 2843 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2844 PetscInt bdof, offset; 2845 2846 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2847 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2848 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2849 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2850 if (dof > 0) { 2851 // State change 2852 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2853 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2854 2855 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2856 // Signal block concatenation 2857 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2858 } 2859 dof = dof < 0 ? -(dof + 1) : dof; 2860 bdof = cdof && (dof - cdof) ? 1 : dof; 2861 if (dof) { 2862 if (bs < 0) { 2863 bs = bdof; 2864 } else if (bs != bdof) { 2865 bs = 1; 2866 } 2867 } 2868 } break; 2869 case DM_BLOCKING_FIELD_NODE: { 2870 for (PetscInt field = 0; field < num_fields; field++) { 2871 PetscInt num_comp, bdof, offset; 2872 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2873 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2874 if (dof < 0) continue; 2875 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2876 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2877 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); 2878 PetscInt num_nodes = dof / num_comp; 2879 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2880 // Handle possibly constant block size (unlikely) 2881 bdof = cdof && (dof - cdof) ? 1 : dof; 2882 if (dof) { 2883 if (bs < 0) { 2884 bs = bdof; 2885 } else if (bs != bdof) { 2886 bs = 1; 2887 } 2888 } 2889 } 2890 } break; 2891 } 2892 } 2893 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2894 /* Must have same blocksize on all procs (some might have no points) */ 2895 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2896 bsLocal[1] = bs; 2897 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2898 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2899 else bs = bsMinMax[0]; 2900 bs = PetscMax(1, bs); 2901 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2902 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2903 PetscCall(MatSetBlockSize(*J, bs)); 2904 PetscCall(MatSetUp(*J)); 2905 } else { 2906 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2907 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2908 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2909 } 2910 if (pblocks) { // Consolidate blocks 2911 PetscInt nblocks = 0; 2912 pblocks[0] = PetscAbs(pblocks[0]); 2913 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2914 if (pblocks[i] == 0) continue; 2915 // Negative block size indicates the blocks should be concatenated 2916 if (pblocks[i] < 0) { 2917 pblocks[i] = -pblocks[i]; 2918 pblocks[nblocks - 1] += pblocks[i]; 2919 } else { 2920 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2921 } 2922 for (PetscInt j = 1; j < pblocks[i]; j++) 2923 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 2924 } 2925 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2926 } 2927 PetscCall(PetscFree(pblocks)); 2928 } 2929 PetscCall(MatSetDM(*J, dm)); 2930 PetscFunctionReturn(PETSC_SUCCESS); 2931 } 2932 2933 /*@ 2934 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2935 2936 Not Collective 2937 2938 Input Parameter: 2939 . dm - The `DMPLEX` 2940 2941 Output Parameter: 2942 . subsection - The subdomain section 2943 2944 Level: developer 2945 2946 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2947 @*/ 2948 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2949 { 2950 DM_Plex *mesh = (DM_Plex *)dm->data; 2951 2952 PetscFunctionBegin; 2953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2954 if (!mesh->subdomainSection) { 2955 PetscSection section; 2956 PetscSF sf; 2957 2958 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2959 PetscCall(DMGetLocalSection(dm, §ion)); 2960 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2961 PetscCall(PetscSFDestroy(&sf)); 2962 } 2963 *subsection = mesh->subdomainSection; 2964 PetscFunctionReturn(PETSC_SUCCESS); 2965 } 2966 2967 /*@ 2968 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2969 2970 Not Collective 2971 2972 Input Parameter: 2973 . dm - The `DMPLEX` 2974 2975 Output Parameters: 2976 + pStart - The first mesh point 2977 - pEnd - The upper bound for mesh points 2978 2979 Level: beginner 2980 2981 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2982 @*/ 2983 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2984 { 2985 DM_Plex *mesh = (DM_Plex *)dm->data; 2986 2987 PetscFunctionBegin; 2988 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2989 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2990 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2991 PetscFunctionReturn(PETSC_SUCCESS); 2992 } 2993 2994 /*@ 2995 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2996 2997 Not Collective 2998 2999 Input Parameters: 3000 + dm - The `DMPLEX` 3001 . pStart - The first mesh point 3002 - pEnd - The upper bound for mesh points 3003 3004 Level: beginner 3005 3006 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3007 @*/ 3008 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3009 { 3010 DM_Plex *mesh = (DM_Plex *)dm->data; 3011 3012 PetscFunctionBegin; 3013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3014 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3015 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3016 PetscCall(PetscFree(mesh->cellTypes)); 3017 PetscFunctionReturn(PETSC_SUCCESS); 3018 } 3019 3020 /*@ 3021 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3022 3023 Not Collective 3024 3025 Input Parameters: 3026 + dm - The `DMPLEX` 3027 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3028 3029 Output Parameter: 3030 . size - The cone size for point `p` 3031 3032 Level: beginner 3033 3034 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3035 @*/ 3036 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3037 { 3038 DM_Plex *mesh = (DM_Plex *)dm->data; 3039 3040 PetscFunctionBegin; 3041 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3042 PetscAssertPointer(size, 3); 3043 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3044 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3045 PetscFunctionReturn(PETSC_SUCCESS); 3046 } 3047 3048 /*@ 3049 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3050 3051 Not Collective 3052 3053 Input Parameters: 3054 + dm - The `DMPLEX` 3055 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3056 - size - The cone size for point `p` 3057 3058 Level: beginner 3059 3060 Note: 3061 This should be called after `DMPlexSetChart()`. 3062 3063 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3064 @*/ 3065 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3066 { 3067 DM_Plex *mesh = (DM_Plex *)dm->data; 3068 3069 PetscFunctionBegin; 3070 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3071 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3072 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3073 PetscFunctionReturn(PETSC_SUCCESS); 3074 } 3075 3076 /*@C 3077 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3078 3079 Not Collective 3080 3081 Input Parameters: 3082 + dm - The `DMPLEX` 3083 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3084 3085 Output Parameter: 3086 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3087 3088 Level: beginner 3089 3090 Fortran Notes: 3091 `cone` must be declared with 3092 .vb 3093 PetscInt, pointer :: cone(:) 3094 .ve 3095 3096 You must also call `DMPlexRestoreCone()` after you finish using the array. 3097 `DMPlexRestoreCone()` is not needed/available in C. 3098 3099 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3100 @*/ 3101 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3102 { 3103 DM_Plex *mesh = (DM_Plex *)dm->data; 3104 PetscInt off; 3105 3106 PetscFunctionBegin; 3107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3108 PetscAssertPointer(cone, 3); 3109 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3110 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3111 PetscFunctionReturn(PETSC_SUCCESS); 3112 } 3113 3114 /*@ 3115 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3116 3117 Not Collective 3118 3119 Input Parameters: 3120 + dm - The `DMPLEX` 3121 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3122 3123 Output Parameters: 3124 + pConesSection - `PetscSection` describing the layout of `pCones` 3125 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3126 3127 Level: intermediate 3128 3129 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3130 @*/ 3131 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3132 { 3133 PetscSection cs, newcs; 3134 PetscInt *cones; 3135 PetscInt *newarr = NULL; 3136 PetscInt n; 3137 3138 PetscFunctionBegin; 3139 PetscCall(DMPlexGetCones(dm, &cones)); 3140 PetscCall(DMPlexGetConeSection(dm, &cs)); 3141 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3142 if (pConesSection) *pConesSection = newcs; 3143 if (pCones) { 3144 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3145 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3146 } 3147 PetscFunctionReturn(PETSC_SUCCESS); 3148 } 3149 3150 /*@ 3151 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3152 3153 Not Collective 3154 3155 Input Parameters: 3156 + dm - The `DMPLEX` 3157 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3158 3159 Output Parameter: 3160 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3161 3162 Level: advanced 3163 3164 Notes: 3165 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3166 3167 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3168 3169 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3170 `DMPlexGetDepth()`, `IS` 3171 @*/ 3172 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3173 { 3174 IS *expandedPointsAll; 3175 PetscInt depth; 3176 3177 PetscFunctionBegin; 3178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3179 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3180 PetscAssertPointer(expandedPoints, 3); 3181 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3182 *expandedPoints = expandedPointsAll[0]; 3183 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3184 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3185 PetscFunctionReturn(PETSC_SUCCESS); 3186 } 3187 3188 /*@ 3189 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3190 (DAG points of depth 0, i.e., without cones). 3191 3192 Not Collective 3193 3194 Input Parameters: 3195 + dm - The `DMPLEX` 3196 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3197 3198 Output Parameters: 3199 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3200 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3201 - sections - (optional) An array of sections which describe mappings from points to their cone points 3202 3203 Level: advanced 3204 3205 Notes: 3206 Like `DMPlexGetConeTuple()` but recursive. 3207 3208 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. 3209 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3210 3211 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\: 3212 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3213 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3214 3215 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3216 `DMPlexGetDepth()`, `PetscSection`, `IS` 3217 @*/ 3218 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3219 { 3220 const PetscInt *arr0 = NULL, *cone = NULL; 3221 PetscInt *arr = NULL, *newarr = NULL; 3222 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3223 IS *expandedPoints_; 3224 PetscSection *sections_; 3225 3226 PetscFunctionBegin; 3227 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3228 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3229 if (depth) PetscAssertPointer(depth, 3); 3230 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3231 if (sections) PetscAssertPointer(sections, 5); 3232 PetscCall(ISGetLocalSize(points, &n)); 3233 PetscCall(ISGetIndices(points, &arr0)); 3234 PetscCall(DMPlexGetDepth(dm, &depth_)); 3235 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3236 PetscCall(PetscCalloc1(depth_, §ions_)); 3237 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3238 for (d = depth_ - 1; d >= 0; d--) { 3239 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3240 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3241 for (i = 0; i < n; i++) { 3242 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3243 if (arr[i] >= start && arr[i] < end) { 3244 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3245 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3246 } else { 3247 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3248 } 3249 } 3250 PetscCall(PetscSectionSetUp(sections_[d])); 3251 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3252 PetscCall(PetscMalloc1(newn, &newarr)); 3253 for (i = 0; i < n; i++) { 3254 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3255 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3256 if (cn > 1) { 3257 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3258 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3259 } else { 3260 newarr[co] = arr[i]; 3261 } 3262 } 3263 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3264 arr = newarr; 3265 n = newn; 3266 } 3267 PetscCall(ISRestoreIndices(points, &arr0)); 3268 *depth = depth_; 3269 if (expandedPoints) *expandedPoints = expandedPoints_; 3270 else { 3271 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3272 PetscCall(PetscFree(expandedPoints_)); 3273 } 3274 if (sections) *sections = sections_; 3275 else { 3276 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3277 PetscCall(PetscFree(sections_)); 3278 } 3279 PetscFunctionReturn(PETSC_SUCCESS); 3280 } 3281 3282 /*@ 3283 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3284 3285 Not Collective 3286 3287 Input Parameters: 3288 + dm - The `DMPLEX` 3289 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3290 3291 Output Parameters: 3292 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3293 . expandedPoints - (optional) An array of recursively expanded cones 3294 - sections - (optional) An array of sections which describe mappings from points to their cone points 3295 3296 Level: advanced 3297 3298 Note: 3299 See `DMPlexGetConeRecursive()` 3300 3301 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3302 `DMPlexGetDepth()`, `IS`, `PetscSection` 3303 @*/ 3304 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3305 { 3306 PetscInt d, depth_; 3307 3308 PetscFunctionBegin; 3309 PetscCall(DMPlexGetDepth(dm, &depth_)); 3310 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3311 if (depth) *depth = 0; 3312 if (expandedPoints) { 3313 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3314 PetscCall(PetscFree(*expandedPoints)); 3315 } 3316 if (sections) { 3317 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3318 PetscCall(PetscFree(*sections)); 3319 } 3320 PetscFunctionReturn(PETSC_SUCCESS); 3321 } 3322 3323 /*@ 3324 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 3325 3326 Not Collective 3327 3328 Input Parameters: 3329 + dm - The `DMPLEX` 3330 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3331 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3332 3333 Level: beginner 3334 3335 Note: 3336 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3337 3338 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3339 @*/ 3340 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3341 { 3342 DM_Plex *mesh = (DM_Plex *)dm->data; 3343 PetscInt dof, off, c; 3344 3345 PetscFunctionBegin; 3346 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3347 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3348 if (dof) PetscAssertPointer(cone, 3); 3349 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3350 if (PetscDefined(USE_DEBUG)) { 3351 PetscInt pStart, pEnd; 3352 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3353 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); 3354 for (c = 0; c < dof; ++c) { 3355 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); 3356 mesh->cones[off + c] = cone[c]; 3357 } 3358 } else { 3359 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3360 } 3361 PetscFunctionReturn(PETSC_SUCCESS); 3362 } 3363 3364 /*@C 3365 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3366 3367 Not Collective 3368 3369 Input Parameters: 3370 + dm - The `DMPLEX` 3371 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3372 3373 Output Parameter: 3374 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3375 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3376 3377 Level: beginner 3378 3379 Note: 3380 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3381 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3382 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3383 with the identity. 3384 3385 Fortran Notes: 3386 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3387 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3388 3389 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3390 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3391 @*/ 3392 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3393 { 3394 DM_Plex *mesh = (DM_Plex *)dm->data; 3395 PetscInt off; 3396 3397 PetscFunctionBegin; 3398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3399 if (PetscDefined(USE_DEBUG)) { 3400 PetscInt dof; 3401 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3402 if (dof) PetscAssertPointer(coneOrientation, 3); 3403 } 3404 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3405 3406 *coneOrientation = &mesh->coneOrientations[off]; 3407 PetscFunctionReturn(PETSC_SUCCESS); 3408 } 3409 3410 /*@ 3411 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3412 3413 Not Collective 3414 3415 Input Parameters: 3416 + dm - The `DMPLEX` 3417 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3418 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3419 3420 Level: beginner 3421 3422 Notes: 3423 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3424 3425 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3426 3427 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3428 @*/ 3429 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3430 { 3431 DM_Plex *mesh = (DM_Plex *)dm->data; 3432 PetscInt pStart, pEnd; 3433 PetscInt dof, off, c; 3434 3435 PetscFunctionBegin; 3436 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3437 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3438 if (dof) PetscAssertPointer(coneOrientation, 3); 3439 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3440 if (PetscDefined(USE_DEBUG)) { 3441 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3442 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); 3443 for (c = 0; c < dof; ++c) { 3444 PetscInt cdof, o = coneOrientation[c]; 3445 3446 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3447 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); 3448 mesh->coneOrientations[off + c] = o; 3449 } 3450 } else { 3451 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3452 } 3453 PetscFunctionReturn(PETSC_SUCCESS); 3454 } 3455 3456 /*@ 3457 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3458 3459 Not Collective 3460 3461 Input Parameters: 3462 + dm - The `DMPLEX` 3463 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3464 . conePos - The local index in the cone where the point should be put 3465 - conePoint - The mesh point to insert 3466 3467 Level: beginner 3468 3469 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3470 @*/ 3471 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3472 { 3473 DM_Plex *mesh = (DM_Plex *)dm->data; 3474 PetscInt pStart, pEnd; 3475 PetscInt dof, off; 3476 3477 PetscFunctionBegin; 3478 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3479 if (PetscDefined(USE_DEBUG)) { 3480 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3481 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); 3482 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); 3483 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3484 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); 3485 } 3486 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3487 mesh->cones[off + conePos] = conePoint; 3488 PetscFunctionReturn(PETSC_SUCCESS); 3489 } 3490 3491 /*@ 3492 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3493 3494 Not Collective 3495 3496 Input Parameters: 3497 + dm - The `DMPLEX` 3498 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3499 . conePos - The local index in the cone where the point should be put 3500 - coneOrientation - The point orientation to insert 3501 3502 Level: beginner 3503 3504 Note: 3505 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3506 3507 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3508 @*/ 3509 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3510 { 3511 DM_Plex *mesh = (DM_Plex *)dm->data; 3512 PetscInt pStart, pEnd; 3513 PetscInt dof, off; 3514 3515 PetscFunctionBegin; 3516 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3517 if (PetscDefined(USE_DEBUG)) { 3518 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3519 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); 3520 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3521 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); 3522 } 3523 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3524 mesh->coneOrientations[off + conePos] = coneOrientation; 3525 PetscFunctionReturn(PETSC_SUCCESS); 3526 } 3527 3528 /*@C 3529 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3530 3531 Not collective 3532 3533 Input Parameters: 3534 + dm - The DMPlex 3535 - p - The point, which must lie in the chart set with DMPlexSetChart() 3536 3537 Output Parameters: 3538 + cone - An array of points which are on the in-edges for point `p` 3539 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3540 integer giving the prescription for cone traversal. 3541 3542 Level: beginner 3543 3544 Notes: 3545 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3546 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3547 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3548 with the identity. 3549 3550 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3551 3552 Fortran Notes: 3553 `cone` and `ornt` must be declared with 3554 .vb 3555 PetscInt, pointer :: cone(:) 3556 PetscInt, pointer :: ornt(:) 3557 .ve 3558 3559 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3560 @*/ 3561 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3562 { 3563 DM_Plex *mesh = (DM_Plex *)dm->data; 3564 3565 PetscFunctionBegin; 3566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3567 if (mesh->tr) { 3568 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3569 } else { 3570 PetscInt off; 3571 if (PetscDefined(USE_DEBUG)) { 3572 PetscInt dof; 3573 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3574 if (dof) { 3575 if (cone) PetscAssertPointer(cone, 3); 3576 if (ornt) PetscAssertPointer(ornt, 4); 3577 } 3578 } 3579 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3580 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3581 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3582 } 3583 PetscFunctionReturn(PETSC_SUCCESS); 3584 } 3585 3586 /*@C 3587 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3588 3589 Not Collective 3590 3591 Input Parameters: 3592 + dm - The DMPlex 3593 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3594 . cone - An array of points which are on the in-edges for point p 3595 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3596 integer giving the prescription for cone traversal. 3597 3598 Level: beginner 3599 3600 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3601 @*/ 3602 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3603 { 3604 DM_Plex *mesh = (DM_Plex *)dm->data; 3605 3606 PetscFunctionBegin; 3607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3608 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3609 PetscFunctionReturn(PETSC_SUCCESS); 3610 } 3611 3612 /*@ 3613 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3614 3615 Not Collective 3616 3617 Input Parameters: 3618 + dm - The `DMPLEX` 3619 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3620 3621 Output Parameter: 3622 . size - The support size for point `p` 3623 3624 Level: beginner 3625 3626 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3627 @*/ 3628 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3629 { 3630 DM_Plex *mesh = (DM_Plex *)dm->data; 3631 3632 PetscFunctionBegin; 3633 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3634 PetscAssertPointer(size, 3); 3635 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3636 PetscFunctionReturn(PETSC_SUCCESS); 3637 } 3638 3639 /*@ 3640 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3641 3642 Not Collective 3643 3644 Input Parameters: 3645 + dm - The `DMPLEX` 3646 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3647 - size - The support size for point `p` 3648 3649 Level: beginner 3650 3651 Note: 3652 This should be called after `DMPlexSetChart()`. 3653 3654 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3655 @*/ 3656 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3657 { 3658 DM_Plex *mesh = (DM_Plex *)dm->data; 3659 3660 PetscFunctionBegin; 3661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3662 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3663 PetscFunctionReturn(PETSC_SUCCESS); 3664 } 3665 3666 /*@C 3667 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3668 3669 Not Collective 3670 3671 Input Parameters: 3672 + dm - The `DMPLEX` 3673 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3674 3675 Output Parameter: 3676 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3677 3678 Level: beginner 3679 3680 Fortran Notes: 3681 `support` must be declared with 3682 .vb 3683 PetscInt, pointer :: support(:) 3684 .ve 3685 3686 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3687 `DMPlexRestoreSupport()` is not needed/available in C. 3688 3689 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3690 @*/ 3691 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3692 { 3693 DM_Plex *mesh = (DM_Plex *)dm->data; 3694 PetscInt off; 3695 3696 PetscFunctionBegin; 3697 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3698 PetscAssertPointer(support, 3); 3699 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3700 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3701 PetscFunctionReturn(PETSC_SUCCESS); 3702 } 3703 3704 /*@ 3705 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3706 3707 Not Collective 3708 3709 Input Parameters: 3710 + dm - The `DMPLEX` 3711 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3712 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3713 3714 Level: beginner 3715 3716 Note: 3717 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3718 3719 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3720 @*/ 3721 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3722 { 3723 DM_Plex *mesh = (DM_Plex *)dm->data; 3724 PetscInt pStart, pEnd; 3725 PetscInt dof, off, c; 3726 3727 PetscFunctionBegin; 3728 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3729 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3730 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3731 if (dof) PetscAssertPointer(support, 3); 3732 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3733 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); 3734 for (c = 0; c < dof; ++c) { 3735 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); 3736 mesh->supports[off + c] = support[c]; 3737 } 3738 PetscFunctionReturn(PETSC_SUCCESS); 3739 } 3740 3741 /*@ 3742 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3743 3744 Not Collective 3745 3746 Input Parameters: 3747 + dm - The `DMPLEX` 3748 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3749 . supportPos - The local index in the cone where the point should be put 3750 - supportPoint - The mesh point to insert 3751 3752 Level: beginner 3753 3754 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3755 @*/ 3756 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3757 { 3758 DM_Plex *mesh = (DM_Plex *)dm->data; 3759 PetscInt pStart, pEnd; 3760 PetscInt dof, off; 3761 3762 PetscFunctionBegin; 3763 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3764 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3765 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3766 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3767 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); 3768 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); 3769 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); 3770 mesh->supports[off + supportPos] = supportPoint; 3771 PetscFunctionReturn(PETSC_SUCCESS); 3772 } 3773 3774 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3775 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3776 { 3777 switch (ct) { 3778 case DM_POLYTOPE_SEGMENT: 3779 if (o == -1) return -2; 3780 break; 3781 case DM_POLYTOPE_TRIANGLE: 3782 if (o == -3) return -1; 3783 if (o == -2) return -3; 3784 if (o == -1) return -2; 3785 break; 3786 case DM_POLYTOPE_QUADRILATERAL: 3787 if (o == -4) return -2; 3788 if (o == -3) return -1; 3789 if (o == -2) return -4; 3790 if (o == -1) return -3; 3791 break; 3792 default: 3793 return o; 3794 } 3795 return o; 3796 } 3797 3798 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3799 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3800 { 3801 switch (ct) { 3802 case DM_POLYTOPE_SEGMENT: 3803 if ((o == -2) || (o == 1)) return -1; 3804 if (o == -1) return 0; 3805 break; 3806 case DM_POLYTOPE_TRIANGLE: 3807 if (o == -3) return -2; 3808 if (o == -2) return -1; 3809 if (o == -1) return -3; 3810 break; 3811 case DM_POLYTOPE_QUADRILATERAL: 3812 if (o == -4) return -2; 3813 if (o == -3) return -1; 3814 if (o == -2) return -4; 3815 if (o == -1) return -3; 3816 break; 3817 default: 3818 return o; 3819 } 3820 return o; 3821 } 3822 3823 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3824 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3825 { 3826 PetscInt pStart, pEnd, p; 3827 3828 PetscFunctionBegin; 3829 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3830 for (p = pStart; p < pEnd; ++p) { 3831 const PetscInt *cone, *ornt; 3832 PetscInt coneSize, c; 3833 3834 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3835 PetscCall(DMPlexGetCone(dm, p, &cone)); 3836 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3837 for (c = 0; c < coneSize; ++c) { 3838 DMPolytopeType ct; 3839 const PetscInt o = ornt[c]; 3840 3841 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3842 switch (ct) { 3843 case DM_POLYTOPE_SEGMENT: 3844 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3845 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3846 break; 3847 case DM_POLYTOPE_TRIANGLE: 3848 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3849 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3850 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3851 break; 3852 case DM_POLYTOPE_QUADRILATERAL: 3853 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3854 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3855 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3856 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3857 break; 3858 default: 3859 break; 3860 } 3861 } 3862 } 3863 PetscFunctionReturn(PETSC_SUCCESS); 3864 } 3865 3866 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3867 { 3868 DM_Plex *mesh = (DM_Plex *)dm->data; 3869 3870 PetscFunctionBeginHot; 3871 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3872 if (useCone) { 3873 PetscCall(DMPlexGetConeSize(dm, p, size)); 3874 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3875 } else { 3876 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3877 PetscCall(DMPlexGetSupport(dm, p, arr)); 3878 } 3879 } else { 3880 if (useCone) { 3881 const PetscSection s = mesh->coneSection; 3882 const PetscInt ps = p - s->pStart; 3883 const PetscInt off = s->atlasOff[ps]; 3884 3885 *size = s->atlasDof[ps]; 3886 *arr = mesh->cones + off; 3887 *ornt = mesh->coneOrientations + off; 3888 } else { 3889 const PetscSection s = mesh->supportSection; 3890 const PetscInt ps = p - s->pStart; 3891 const PetscInt off = s->atlasOff[ps]; 3892 3893 *size = s->atlasDof[ps]; 3894 *arr = mesh->supports + off; 3895 } 3896 } 3897 PetscFunctionReturn(PETSC_SUCCESS); 3898 } 3899 3900 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3901 { 3902 DM_Plex *mesh = (DM_Plex *)dm->data; 3903 3904 PetscFunctionBeginHot; 3905 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3906 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3907 } 3908 PetscFunctionReturn(PETSC_SUCCESS); 3909 } 3910 3911 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3912 { 3913 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3914 PetscInt *closure; 3915 const PetscInt *tmp = NULL, *tmpO = NULL; 3916 PetscInt off = 0, tmpSize, t; 3917 3918 PetscFunctionBeginHot; 3919 if (ornt) { 3920 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3921 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; 3922 } 3923 if (*points) { 3924 closure = *points; 3925 } else { 3926 PetscInt maxConeSize, maxSupportSize; 3927 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3928 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3929 } 3930 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3931 if (ct == DM_POLYTOPE_UNKNOWN) { 3932 closure[off++] = p; 3933 closure[off++] = 0; 3934 for (t = 0; t < tmpSize; ++t) { 3935 closure[off++] = tmp[t]; 3936 closure[off++] = tmpO ? tmpO[t] : 0; 3937 } 3938 } else { 3939 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3940 3941 /* We assume that cells with a valid type have faces with a valid type */ 3942 closure[off++] = p; 3943 closure[off++] = ornt; 3944 for (t = 0; t < tmpSize; ++t) { 3945 DMPolytopeType ft; 3946 3947 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3948 closure[off++] = tmp[arr[t]]; 3949 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3950 } 3951 } 3952 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3953 if (numPoints) *numPoints = tmpSize + 1; 3954 if (points) *points = closure; 3955 PetscFunctionReturn(PETSC_SUCCESS); 3956 } 3957 3958 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3959 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3960 { 3961 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3962 const PetscInt *cone, *ornt; 3963 PetscInt *pts, *closure = NULL; 3964 DMPolytopeType ft; 3965 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3966 PetscInt dim, coneSize, c, d, clSize, cl; 3967 3968 PetscFunctionBeginHot; 3969 PetscCall(DMGetDimension(dm, &dim)); 3970 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3971 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3972 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3973 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3974 maxSize = PetscMax(coneSeries, supportSeries); 3975 if (*points) { 3976 pts = *points; 3977 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3978 c = 0; 3979 pts[c++] = point; 3980 pts[c++] = o; 3981 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3982 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3983 for (cl = 0; cl < clSize * 2; cl += 2) { 3984 pts[c++] = closure[cl]; 3985 pts[c++] = closure[cl + 1]; 3986 } 3987 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3988 for (cl = 0; cl < clSize * 2; cl += 2) { 3989 pts[c++] = closure[cl]; 3990 pts[c++] = closure[cl + 1]; 3991 } 3992 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3993 for (d = 2; d < coneSize; ++d) { 3994 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3995 pts[c++] = cone[arr[d * 2 + 0]]; 3996 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3997 } 3998 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3999 if (dim >= 3) { 4000 for (d = 2; d < coneSize; ++d) { 4001 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4002 const PetscInt *fcone, *fornt; 4003 PetscInt fconeSize, fc, i; 4004 4005 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4006 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4007 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4008 for (fc = 0; fc < fconeSize; ++fc) { 4009 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4010 const PetscInt co = farr[fc * 2 + 1]; 4011 4012 for (i = 0; i < c; i += 2) 4013 if (pts[i] == cp) break; 4014 if (i == c) { 4015 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4016 pts[c++] = cp; 4017 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4018 } 4019 } 4020 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4021 } 4022 } 4023 *numPoints = c / 2; 4024 *points = pts; 4025 PetscFunctionReturn(PETSC_SUCCESS); 4026 } 4027 4028 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4029 { 4030 DMPolytopeType ct; 4031 PetscInt *closure, *fifo; 4032 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4033 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4034 PetscInt depth, maxSize; 4035 4036 PetscFunctionBeginHot; 4037 PetscCall(DMPlexGetDepth(dm, &depth)); 4038 if (depth == 1) { 4039 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4040 PetscFunctionReturn(PETSC_SUCCESS); 4041 } 4042 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4043 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; 4044 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4045 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4046 PetscFunctionReturn(PETSC_SUCCESS); 4047 } 4048 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4049 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4050 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4051 maxSize = PetscMax(coneSeries, supportSeries); 4052 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4053 if (*points) { 4054 closure = *points; 4055 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4056 closure[closureSize++] = p; 4057 closure[closureSize++] = ornt; 4058 fifo[fifoSize++] = p; 4059 fifo[fifoSize++] = ornt; 4060 fifo[fifoSize++] = ct; 4061 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4062 while (fifoSize - fifoStart) { 4063 const PetscInt q = fifo[fifoStart++]; 4064 const PetscInt o = fifo[fifoStart++]; 4065 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4066 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4067 const PetscInt *tmp, *tmpO = NULL; 4068 PetscInt tmpSize, t; 4069 4070 if (PetscDefined(USE_DEBUG)) { 4071 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4072 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); 4073 } 4074 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4075 for (t = 0; t < tmpSize; ++t) { 4076 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4077 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4078 const PetscInt cp = tmp[ip]; 4079 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4080 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4081 PetscInt c; 4082 4083 /* Check for duplicate */ 4084 for (c = 0; c < closureSize; c += 2) { 4085 if (closure[c] == cp) break; 4086 } 4087 if (c == closureSize) { 4088 closure[closureSize++] = cp; 4089 closure[closureSize++] = co; 4090 fifo[fifoSize++] = cp; 4091 fifo[fifoSize++] = co; 4092 fifo[fifoSize++] = ct; 4093 } 4094 } 4095 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4096 } 4097 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4098 if (numPoints) *numPoints = closureSize / 2; 4099 if (points) *points = closure; 4100 PetscFunctionReturn(PETSC_SUCCESS); 4101 } 4102 4103 /*@C 4104 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4105 4106 Not Collective 4107 4108 Input Parameters: 4109 + dm - The `DMPLEX` 4110 . p - The mesh point 4111 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4112 4113 Input/Output Parameter: 4114 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4115 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4116 otherwise the provided array is used to hold the values 4117 4118 Output Parameter: 4119 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4120 4121 Level: beginner 4122 4123 Note: 4124 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4125 4126 Fortran Notes: 4127 `points` must be declared with 4128 .vb 4129 PetscInt, pointer :: points(:) 4130 .ve 4131 and is always allocated by the function. 4132 4133 The `numPoints` argument is not present in the Fortran binding. 4134 4135 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4136 @*/ 4137 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4138 { 4139 PetscFunctionBeginHot; 4140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4141 if (numPoints) PetscAssertPointer(numPoints, 4); 4142 if (points) PetscAssertPointer(points, 5); 4143 if (PetscDefined(USE_DEBUG)) { 4144 PetscInt pStart, pEnd; 4145 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4146 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4147 } 4148 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4149 PetscFunctionReturn(PETSC_SUCCESS); 4150 } 4151 4152 /*@C 4153 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4154 4155 Not Collective 4156 4157 Input Parameters: 4158 + dm - The `DMPLEX` 4159 . p - The mesh point 4160 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4161 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4162 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4163 4164 Level: beginner 4165 4166 Note: 4167 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4168 4169 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4170 @*/ 4171 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4172 { 4173 PetscFunctionBeginHot; 4174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4175 if (numPoints) *numPoints = 0; 4176 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4177 PetscFunctionReturn(PETSC_SUCCESS); 4178 } 4179 4180 /*@ 4181 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4182 4183 Not Collective 4184 4185 Input Parameter: 4186 . dm - The `DMPLEX` 4187 4188 Output Parameters: 4189 + maxConeSize - The maximum number of in-edges 4190 - maxSupportSize - The maximum number of out-edges 4191 4192 Level: beginner 4193 4194 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4195 @*/ 4196 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4197 { 4198 DM_Plex *mesh = (DM_Plex *)dm->data; 4199 4200 PetscFunctionBegin; 4201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4202 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4203 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4204 PetscFunctionReturn(PETSC_SUCCESS); 4205 } 4206 4207 PetscErrorCode DMSetUp_Plex(DM dm) 4208 { 4209 DM_Plex *mesh = (DM_Plex *)dm->data; 4210 PetscInt size, maxSupportSize; 4211 4212 PetscFunctionBegin; 4213 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4214 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4215 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4216 PetscCall(PetscMalloc1(size, &mesh->cones)); 4217 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4218 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4219 if (maxSupportSize) { 4220 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4221 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4222 PetscCall(PetscMalloc1(size, &mesh->supports)); 4223 } 4224 PetscFunctionReturn(PETSC_SUCCESS); 4225 } 4226 4227 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4228 { 4229 PetscFunctionBegin; 4230 if (subdm) PetscCall(DMClone(dm, subdm)); 4231 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4232 if (subdm) (*subdm)->useNatural = dm->useNatural; 4233 if (dm->useNatural && dm->sfMigration) { 4234 PetscSF sfNatural; 4235 4236 (*subdm)->sfMigration = dm->sfMigration; 4237 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4238 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4239 (*subdm)->sfNatural = sfNatural; 4240 } 4241 PetscFunctionReturn(PETSC_SUCCESS); 4242 } 4243 4244 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4245 { 4246 PetscInt i = 0; 4247 4248 PetscFunctionBegin; 4249 PetscCall(DMClone(dms[0], superdm)); 4250 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4251 (*superdm)->useNatural = PETSC_FALSE; 4252 for (i = 0; i < len; i++) { 4253 if (dms[i]->useNatural && dms[i]->sfMigration) { 4254 PetscSF sfNatural; 4255 4256 (*superdm)->sfMigration = dms[i]->sfMigration; 4257 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4258 (*superdm)->useNatural = PETSC_TRUE; 4259 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4260 (*superdm)->sfNatural = sfNatural; 4261 break; 4262 } 4263 } 4264 PetscFunctionReturn(PETSC_SUCCESS); 4265 } 4266 4267 /*@ 4268 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4269 4270 Not Collective 4271 4272 Input Parameter: 4273 . dm - The `DMPLEX` 4274 4275 Level: beginner 4276 4277 Note: 4278 This should be called after all calls to `DMPlexSetCone()` 4279 4280 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4281 @*/ 4282 PetscErrorCode DMPlexSymmetrize(DM dm) 4283 { 4284 DM_Plex *mesh = (DM_Plex *)dm->data; 4285 PetscInt *offsets; 4286 PetscInt supportSize; 4287 PetscInt pStart, pEnd, p; 4288 4289 PetscFunctionBegin; 4290 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4291 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4292 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4293 /* Calculate support sizes */ 4294 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4295 for (p = pStart; p < pEnd; ++p) { 4296 PetscInt dof, off, c; 4297 4298 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4299 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4300 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4301 } 4302 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4303 /* Calculate supports */ 4304 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4305 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4306 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4307 for (p = pStart; p < pEnd; ++p) { 4308 PetscInt dof, off, c; 4309 4310 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4311 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4312 for (c = off; c < off + dof; ++c) { 4313 const PetscInt q = mesh->cones[c]; 4314 PetscInt offS; 4315 4316 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4317 4318 mesh->supports[offS + offsets[q]] = p; 4319 ++offsets[q]; 4320 } 4321 } 4322 PetscCall(PetscFree(offsets)); 4323 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4324 PetscFunctionReturn(PETSC_SUCCESS); 4325 } 4326 4327 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4328 { 4329 IS stratumIS; 4330 4331 PetscFunctionBegin; 4332 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4333 if (PetscDefined(USE_DEBUG)) { 4334 PetscInt qStart, qEnd, numLevels, level; 4335 PetscBool overlap = PETSC_FALSE; 4336 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4337 for (level = 0; level < numLevels; level++) { 4338 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4339 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4340 overlap = PETSC_TRUE; 4341 break; 4342 } 4343 } 4344 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); 4345 } 4346 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4347 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4348 PetscCall(ISDestroy(&stratumIS)); 4349 PetscFunctionReturn(PETSC_SUCCESS); 4350 } 4351 4352 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4353 { 4354 PetscInt *pMin, *pMax; 4355 PetscInt pStart, pEnd; 4356 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4357 4358 PetscFunctionBegin; 4359 { 4360 DMLabel label2; 4361 4362 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4363 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4364 } 4365 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4366 for (PetscInt p = pStart; p < pEnd; ++p) { 4367 DMPolytopeType ct; 4368 4369 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4370 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4371 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4372 } 4373 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4374 for (PetscInt d = dmin; d <= dmax; ++d) { 4375 pMin[d] = PETSC_MAX_INT; 4376 pMax[d] = PETSC_MIN_INT; 4377 } 4378 for (PetscInt p = pStart; p < pEnd; ++p) { 4379 DMPolytopeType ct; 4380 PetscInt d; 4381 4382 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4383 d = DMPolytopeTypeGetDim(ct); 4384 pMin[d] = PetscMin(p, pMin[d]); 4385 pMax[d] = PetscMax(p, pMax[d]); 4386 } 4387 for (PetscInt d = dmin; d <= dmax; ++d) { 4388 if (pMin[d] > pMax[d]) continue; 4389 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4390 } 4391 PetscCall(PetscFree2(pMin, pMax)); 4392 PetscFunctionReturn(PETSC_SUCCESS); 4393 } 4394 4395 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4396 { 4397 PetscInt pStart, pEnd; 4398 PetscInt numRoots = 0, numLeaves = 0; 4399 4400 PetscFunctionBegin; 4401 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4402 { 4403 /* Initialize roots and count leaves */ 4404 PetscInt sMin = PETSC_MAX_INT; 4405 PetscInt sMax = PETSC_MIN_INT; 4406 PetscInt coneSize, supportSize; 4407 4408 for (PetscInt p = pStart; p < pEnd; ++p) { 4409 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4410 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4411 if (!coneSize && supportSize) { 4412 sMin = PetscMin(p, sMin); 4413 sMax = PetscMax(p, sMax); 4414 ++numRoots; 4415 } else if (!supportSize && coneSize) { 4416 ++numLeaves; 4417 } else if (!supportSize && !coneSize) { 4418 /* Isolated points */ 4419 sMin = PetscMin(p, sMin); 4420 sMax = PetscMax(p, sMax); 4421 } 4422 } 4423 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4424 } 4425 4426 if (numRoots + numLeaves == (pEnd - pStart)) { 4427 PetscInt sMin = PETSC_MAX_INT; 4428 PetscInt sMax = PETSC_MIN_INT; 4429 PetscInt coneSize, supportSize; 4430 4431 for (PetscInt p = pStart; p < pEnd; ++p) { 4432 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4433 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4434 if (!supportSize && coneSize) { 4435 sMin = PetscMin(p, sMin); 4436 sMax = PetscMax(p, sMax); 4437 } 4438 } 4439 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4440 } else { 4441 PetscInt level = 0; 4442 PetscInt qStart, qEnd; 4443 4444 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4445 while (qEnd > qStart) { 4446 PetscInt sMin = PETSC_MAX_INT; 4447 PetscInt sMax = PETSC_MIN_INT; 4448 4449 for (PetscInt q = qStart; q < qEnd; ++q) { 4450 const PetscInt *support; 4451 PetscInt supportSize; 4452 4453 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4454 PetscCall(DMPlexGetSupport(dm, q, &support)); 4455 for (PetscInt s = 0; s < supportSize; ++s) { 4456 sMin = PetscMin(support[s], sMin); 4457 sMax = PetscMax(support[s], sMax); 4458 } 4459 } 4460 PetscCall(DMLabelGetNumValues(label, &level)); 4461 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4462 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4463 } 4464 } 4465 PetscFunctionReturn(PETSC_SUCCESS); 4466 } 4467 4468 /*@ 4469 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4470 4471 Collective 4472 4473 Input Parameter: 4474 . dm - The `DMPLEX` 4475 4476 Level: beginner 4477 4478 Notes: 4479 The strata group all points of the same grade, and this function calculates the strata. This 4480 grade can be seen as the height (or depth) of the point in the DAG. 4481 4482 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4483 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4484 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4485 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4486 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4487 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4488 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4489 4490 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4491 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4492 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 4493 to interpolate only that one (e0), so that 4494 .vb 4495 cone(c0) = {e0, v2} 4496 cone(e0) = {v0, v1} 4497 .ve 4498 If `DMPlexStratify()` is run on this mesh, it will give depths 4499 .vb 4500 depth 0 = {v0, v1, v2} 4501 depth 1 = {e0, c0} 4502 .ve 4503 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4504 4505 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4506 4507 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4508 @*/ 4509 PetscErrorCode DMPlexStratify(DM dm) 4510 { 4511 DM_Plex *mesh = (DM_Plex *)dm->data; 4512 DMLabel label; 4513 PetscBool flg = PETSC_FALSE; 4514 4515 PetscFunctionBegin; 4516 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4517 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4518 4519 // Create depth label 4520 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4521 PetscCall(DMCreateLabel(dm, "depth")); 4522 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4523 4524 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4525 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4526 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4527 4528 { /* just in case there is an empty process */ 4529 PetscInt numValues, maxValues = 0, v; 4530 4531 PetscCall(DMLabelGetNumValues(label, &numValues)); 4532 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4533 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4534 } 4535 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4536 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4537 PetscFunctionReturn(PETSC_SUCCESS); 4538 } 4539 4540 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4541 { 4542 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4543 PetscInt dim, depth, pheight, coneSize; 4544 4545 PetscFunctionBeginHot; 4546 PetscCall(DMGetDimension(dm, &dim)); 4547 PetscCall(DMPlexGetDepth(dm, &depth)); 4548 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4549 pheight = depth - pdepth; 4550 if (depth <= 1) { 4551 switch (pdepth) { 4552 case 0: 4553 ct = DM_POLYTOPE_POINT; 4554 break; 4555 case 1: 4556 switch (coneSize) { 4557 case 2: 4558 ct = DM_POLYTOPE_SEGMENT; 4559 break; 4560 case 3: 4561 ct = DM_POLYTOPE_TRIANGLE; 4562 break; 4563 case 4: 4564 switch (dim) { 4565 case 2: 4566 ct = DM_POLYTOPE_QUADRILATERAL; 4567 break; 4568 case 3: 4569 ct = DM_POLYTOPE_TETRAHEDRON; 4570 break; 4571 default: 4572 break; 4573 } 4574 break; 4575 case 5: 4576 ct = DM_POLYTOPE_PYRAMID; 4577 break; 4578 case 6: 4579 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4580 break; 4581 case 8: 4582 ct = DM_POLYTOPE_HEXAHEDRON; 4583 break; 4584 default: 4585 break; 4586 } 4587 } 4588 } else { 4589 if (pdepth == 0) { 4590 ct = DM_POLYTOPE_POINT; 4591 } else if (pheight == 0) { 4592 switch (dim) { 4593 case 1: 4594 switch (coneSize) { 4595 case 2: 4596 ct = DM_POLYTOPE_SEGMENT; 4597 break; 4598 default: 4599 break; 4600 } 4601 break; 4602 case 2: 4603 switch (coneSize) { 4604 case 3: 4605 ct = DM_POLYTOPE_TRIANGLE; 4606 break; 4607 case 4: 4608 ct = DM_POLYTOPE_QUADRILATERAL; 4609 break; 4610 default: 4611 break; 4612 } 4613 break; 4614 case 3: 4615 switch (coneSize) { 4616 case 4: 4617 ct = DM_POLYTOPE_TETRAHEDRON; 4618 break; 4619 case 5: { 4620 const PetscInt *cone; 4621 PetscInt faceConeSize; 4622 4623 PetscCall(DMPlexGetCone(dm, p, &cone)); 4624 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4625 switch (faceConeSize) { 4626 case 3: 4627 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4628 break; 4629 case 4: 4630 ct = DM_POLYTOPE_PYRAMID; 4631 break; 4632 } 4633 } break; 4634 case 6: 4635 ct = DM_POLYTOPE_HEXAHEDRON; 4636 break; 4637 default: 4638 break; 4639 } 4640 break; 4641 default: 4642 break; 4643 } 4644 } else if (pheight > 0) { 4645 switch (coneSize) { 4646 case 2: 4647 ct = DM_POLYTOPE_SEGMENT; 4648 break; 4649 case 3: 4650 ct = DM_POLYTOPE_TRIANGLE; 4651 break; 4652 case 4: 4653 ct = DM_POLYTOPE_QUADRILATERAL; 4654 break; 4655 default: 4656 break; 4657 } 4658 } 4659 } 4660 *pt = ct; 4661 PetscFunctionReturn(PETSC_SUCCESS); 4662 } 4663 4664 /*@ 4665 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4666 4667 Collective 4668 4669 Input Parameter: 4670 . dm - The `DMPLEX` 4671 4672 Level: developer 4673 4674 Note: 4675 This function is normally called automatically when a cell type is requested. It creates an 4676 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4677 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4678 4679 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4680 4681 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4682 @*/ 4683 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4684 { 4685 DM_Plex *mesh; 4686 DMLabel ctLabel; 4687 PetscInt pStart, pEnd, p; 4688 4689 PetscFunctionBegin; 4690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4691 mesh = (DM_Plex *)dm->data; 4692 PetscCall(DMCreateLabel(dm, "celltype")); 4693 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4694 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4695 PetscCall(PetscFree(mesh->cellTypes)); 4696 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4697 for (p = pStart; p < pEnd; ++p) { 4698 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4699 PetscInt pdepth; 4700 4701 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4702 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4703 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]); 4704 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4705 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4706 } 4707 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4708 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4709 PetscFunctionReturn(PETSC_SUCCESS); 4710 } 4711 4712 /*@C 4713 DMPlexGetJoin - Get an array for the join of the set of points 4714 4715 Not Collective 4716 4717 Input Parameters: 4718 + dm - The `DMPLEX` object 4719 . numPoints - The number of input points for the join 4720 - points - The input points 4721 4722 Output Parameters: 4723 + numCoveredPoints - The number of points in the join 4724 - coveredPoints - The points in the join 4725 4726 Level: intermediate 4727 4728 Note: 4729 Currently, this is restricted to a single level join 4730 4731 Fortran Notes: 4732 `converedPoints` must be declared with 4733 .vb 4734 PetscInt, pointer :: coveredPints(:) 4735 .ve 4736 4737 The `numCoveredPoints` argument is not present in the Fortran binding. 4738 4739 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4740 @*/ 4741 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4742 { 4743 DM_Plex *mesh = (DM_Plex *)dm->data; 4744 PetscInt *join[2]; 4745 PetscInt joinSize, i = 0; 4746 PetscInt dof, off, p, c, m; 4747 PetscInt maxSupportSize; 4748 4749 PetscFunctionBegin; 4750 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4751 PetscAssertPointer(points, 3); 4752 PetscAssertPointer(numCoveredPoints, 4); 4753 PetscAssertPointer(coveredPoints, 5); 4754 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4755 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4756 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4757 /* Copy in support of first point */ 4758 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4759 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4760 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4761 /* Check each successive support */ 4762 for (p = 1; p < numPoints; ++p) { 4763 PetscInt newJoinSize = 0; 4764 4765 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4766 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4767 for (c = 0; c < dof; ++c) { 4768 const PetscInt point = mesh->supports[off + c]; 4769 4770 for (m = 0; m < joinSize; ++m) { 4771 if (point == join[i][m]) { 4772 join[1 - i][newJoinSize++] = point; 4773 break; 4774 } 4775 } 4776 } 4777 joinSize = newJoinSize; 4778 i = 1 - i; 4779 } 4780 *numCoveredPoints = joinSize; 4781 *coveredPoints = join[i]; 4782 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4783 PetscFunctionReturn(PETSC_SUCCESS); 4784 } 4785 4786 /*@C 4787 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4788 4789 Not Collective 4790 4791 Input Parameters: 4792 + dm - The `DMPLEX` object 4793 . numPoints - The number of input points for the join 4794 - points - The input points 4795 4796 Output Parameters: 4797 + numCoveredPoints - The number of points in the join 4798 - coveredPoints - The points in the join 4799 4800 Level: intermediate 4801 4802 Fortran Notes: 4803 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4804 4805 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4806 @*/ 4807 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4808 { 4809 PetscFunctionBegin; 4810 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4811 if (points) PetscAssertPointer(points, 3); 4812 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4813 PetscAssertPointer(coveredPoints, 5); 4814 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4815 if (numCoveredPoints) *numCoveredPoints = 0; 4816 PetscFunctionReturn(PETSC_SUCCESS); 4817 } 4818 4819 /*@C 4820 DMPlexGetFullJoin - Get an array for the join of the set of points 4821 4822 Not Collective 4823 4824 Input Parameters: 4825 + dm - The `DMPLEX` object 4826 . numPoints - The number of input points for the join 4827 - points - The input points, its length is `numPoints` 4828 4829 Output Parameters: 4830 + numCoveredPoints - The number of points in the join 4831 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4832 4833 Level: intermediate 4834 4835 Fortran Notes: 4836 `points` and `converedPoints` must be declared with 4837 .vb 4838 PetscInt, pointer :: points(:) 4839 PetscInt, pointer :: coveredPints(:) 4840 .ve 4841 4842 The `numCoveredPoints` argument is not present in the Fortran binding. 4843 4844 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4845 @*/ 4846 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4847 { 4848 PetscInt *offsets, **closures; 4849 PetscInt *join[2]; 4850 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4851 PetscInt p, d, c, m, ms; 4852 4853 PetscFunctionBegin; 4854 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4855 PetscAssertPointer(points, 3); 4856 PetscAssertPointer(numCoveredPoints, 4); 4857 PetscAssertPointer(coveredPoints, 5); 4858 4859 PetscCall(DMPlexGetDepth(dm, &depth)); 4860 PetscCall(PetscCalloc1(numPoints, &closures)); 4861 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4862 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4863 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4864 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4865 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4866 4867 for (p = 0; p < numPoints; ++p) { 4868 PetscInt closureSize; 4869 4870 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4871 4872 offsets[p * (depth + 2) + 0] = 0; 4873 for (d = 0; d < depth + 1; ++d) { 4874 PetscInt pStart, pEnd, i; 4875 4876 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4877 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4878 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4879 offsets[p * (depth + 2) + d + 1] = i; 4880 break; 4881 } 4882 } 4883 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4884 } 4885 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); 4886 } 4887 for (d = 0; d < depth + 1; ++d) { 4888 PetscInt dof; 4889 4890 /* Copy in support of first point */ 4891 dof = offsets[d + 1] - offsets[d]; 4892 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4893 /* Check each successive cone */ 4894 for (p = 1; p < numPoints && joinSize; ++p) { 4895 PetscInt newJoinSize = 0; 4896 4897 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4898 for (c = 0; c < dof; ++c) { 4899 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4900 4901 for (m = 0; m < joinSize; ++m) { 4902 if (point == join[i][m]) { 4903 join[1 - i][newJoinSize++] = point; 4904 break; 4905 } 4906 } 4907 } 4908 joinSize = newJoinSize; 4909 i = 1 - i; 4910 } 4911 if (joinSize) break; 4912 } 4913 *numCoveredPoints = joinSize; 4914 *coveredPoints = join[i]; 4915 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4916 PetscCall(PetscFree(closures)); 4917 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4918 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4919 PetscFunctionReturn(PETSC_SUCCESS); 4920 } 4921 4922 /*@C 4923 DMPlexGetMeet - Get an array for the meet of the set of points 4924 4925 Not Collective 4926 4927 Input Parameters: 4928 + dm - The `DMPLEX` object 4929 . numPoints - The number of input points for the meet 4930 - points - The input points, of length `numPoints` 4931 4932 Output Parameters: 4933 + numCoveringPoints - The number of points in the meet 4934 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4935 4936 Level: intermediate 4937 4938 Note: 4939 Currently, this is restricted to a single level meet 4940 4941 Fortran Notes: 4942 `coveringPoints` must be declared with 4943 .vb 4944 PetscInt, pointer :: coveringPoints(:) 4945 .ve 4946 4947 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4948 4949 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4950 @*/ 4951 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4952 { 4953 DM_Plex *mesh = (DM_Plex *)dm->data; 4954 PetscInt *meet[2]; 4955 PetscInt meetSize, i = 0; 4956 PetscInt dof, off, p, c, m; 4957 PetscInt maxConeSize; 4958 4959 PetscFunctionBegin; 4960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4961 PetscAssertPointer(points, 3); 4962 PetscAssertPointer(numCoveringPoints, 4); 4963 PetscAssertPointer(coveringPoints, 5); 4964 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4965 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4966 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4967 /* Copy in cone of first point */ 4968 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4969 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4970 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4971 /* Check each successive cone */ 4972 for (p = 1; p < numPoints; ++p) { 4973 PetscInt newMeetSize = 0; 4974 4975 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4976 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4977 for (c = 0; c < dof; ++c) { 4978 const PetscInt point = mesh->cones[off + c]; 4979 4980 for (m = 0; m < meetSize; ++m) { 4981 if (point == meet[i][m]) { 4982 meet[1 - i][newMeetSize++] = point; 4983 break; 4984 } 4985 } 4986 } 4987 meetSize = newMeetSize; 4988 i = 1 - i; 4989 } 4990 *numCoveringPoints = meetSize; 4991 *coveringPoints = meet[i]; 4992 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4993 PetscFunctionReturn(PETSC_SUCCESS); 4994 } 4995 4996 /*@C 4997 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 4998 4999 Not Collective 5000 5001 Input Parameters: 5002 + dm - The `DMPLEX` object 5003 . numPoints - The number of input points for the meet 5004 - points - The input points 5005 5006 Output Parameters: 5007 + numCoveredPoints - The number of points in the meet 5008 - coveredPoints - The points in the meet 5009 5010 Level: intermediate 5011 5012 Fortran Notes: 5013 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5014 5015 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5016 @*/ 5017 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5018 { 5019 PetscFunctionBegin; 5020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5021 if (points) PetscAssertPointer(points, 3); 5022 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5023 PetscAssertPointer(coveredPoints, 5); 5024 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5025 if (numCoveredPoints) *numCoveredPoints = 0; 5026 PetscFunctionReturn(PETSC_SUCCESS); 5027 } 5028 5029 /*@C 5030 DMPlexGetFullMeet - Get an array for the meet of the set of points 5031 5032 Not Collective 5033 5034 Input Parameters: 5035 + dm - The `DMPLEX` object 5036 . numPoints - The number of input points for the meet 5037 - points - The input points, of length `numPoints` 5038 5039 Output Parameters: 5040 + numCoveredPoints - The number of points in the meet 5041 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5042 5043 Level: intermediate 5044 5045 Fortran Notes: 5046 `points` and `coveredPoints` must be declared with 5047 .vb 5048 PetscInt, pointer :: points(:) 5049 PetscInt, pointer :: coveredPoints(:) 5050 .ve 5051 5052 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5053 5054 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5055 @*/ 5056 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5057 { 5058 PetscInt *offsets, **closures; 5059 PetscInt *meet[2]; 5060 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5061 PetscInt p, h, c, m, mc; 5062 5063 PetscFunctionBegin; 5064 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5065 PetscAssertPointer(points, 3); 5066 PetscAssertPointer(numCoveredPoints, 4); 5067 PetscAssertPointer(coveredPoints, 5); 5068 5069 PetscCall(DMPlexGetDepth(dm, &height)); 5070 PetscCall(PetscMalloc1(numPoints, &closures)); 5071 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5072 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5073 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5074 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5075 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5076 5077 for (p = 0; p < numPoints; ++p) { 5078 PetscInt closureSize; 5079 5080 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5081 5082 offsets[p * (height + 2) + 0] = 0; 5083 for (h = 0; h < height + 1; ++h) { 5084 PetscInt pStart, pEnd, i; 5085 5086 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5087 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5088 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5089 offsets[p * (height + 2) + h + 1] = i; 5090 break; 5091 } 5092 } 5093 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5094 } 5095 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); 5096 } 5097 for (h = 0; h < height + 1; ++h) { 5098 PetscInt dof; 5099 5100 /* Copy in cone of first point */ 5101 dof = offsets[h + 1] - offsets[h]; 5102 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5103 /* Check each successive cone */ 5104 for (p = 1; p < numPoints && meetSize; ++p) { 5105 PetscInt newMeetSize = 0; 5106 5107 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5108 for (c = 0; c < dof; ++c) { 5109 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5110 5111 for (m = 0; m < meetSize; ++m) { 5112 if (point == meet[i][m]) { 5113 meet[1 - i][newMeetSize++] = point; 5114 break; 5115 } 5116 } 5117 } 5118 meetSize = newMeetSize; 5119 i = 1 - i; 5120 } 5121 if (meetSize) break; 5122 } 5123 *numCoveredPoints = meetSize; 5124 *coveredPoints = meet[i]; 5125 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5126 PetscCall(PetscFree(closures)); 5127 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5128 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5129 PetscFunctionReturn(PETSC_SUCCESS); 5130 } 5131 5132 /*@ 5133 DMPlexEqual - Determine if two `DM` have the same topology 5134 5135 Not Collective 5136 5137 Input Parameters: 5138 + dmA - A `DMPLEX` object 5139 - dmB - A `DMPLEX` object 5140 5141 Output Parameter: 5142 . equal - `PETSC_TRUE` if the topologies are identical 5143 5144 Level: intermediate 5145 5146 Note: 5147 We are not solving graph isomorphism, so we do not permute. 5148 5149 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5150 @*/ 5151 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5152 { 5153 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5154 5155 PetscFunctionBegin; 5156 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5157 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5158 PetscAssertPointer(equal, 3); 5159 5160 *equal = PETSC_FALSE; 5161 PetscCall(DMPlexGetDepth(dmA, &depth)); 5162 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5163 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5164 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5165 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5166 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5167 for (p = pStart; p < pEnd; ++p) { 5168 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5169 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5170 5171 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5172 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5173 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5174 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5175 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5176 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5177 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5178 for (c = 0; c < coneSize; ++c) { 5179 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5180 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5181 } 5182 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5183 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5184 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5185 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5186 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5187 for (s = 0; s < supportSize; ++s) { 5188 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5189 } 5190 } 5191 *equal = PETSC_TRUE; 5192 PetscFunctionReturn(PETSC_SUCCESS); 5193 } 5194 5195 /*@ 5196 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5197 5198 Not Collective 5199 5200 Input Parameters: 5201 + dm - The `DMPLEX` 5202 . cellDim - The cell dimension 5203 - numCorners - The number of vertices on a cell 5204 5205 Output Parameter: 5206 . numFaceVertices - The number of vertices on a face 5207 5208 Level: developer 5209 5210 Note: 5211 Of course this can only work for a restricted set of symmetric shapes 5212 5213 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5214 @*/ 5215 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5216 { 5217 MPI_Comm comm; 5218 5219 PetscFunctionBegin; 5220 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5221 PetscAssertPointer(numFaceVertices, 4); 5222 switch (cellDim) { 5223 case 0: 5224 *numFaceVertices = 0; 5225 break; 5226 case 1: 5227 *numFaceVertices = 1; 5228 break; 5229 case 2: 5230 switch (numCorners) { 5231 case 3: /* triangle */ 5232 *numFaceVertices = 2; /* Edge has 2 vertices */ 5233 break; 5234 case 4: /* quadrilateral */ 5235 *numFaceVertices = 2; /* Edge has 2 vertices */ 5236 break; 5237 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5238 *numFaceVertices = 3; /* Edge has 3 vertices */ 5239 break; 5240 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5241 *numFaceVertices = 3; /* Edge has 3 vertices */ 5242 break; 5243 default: 5244 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5245 } 5246 break; 5247 case 3: 5248 switch (numCorners) { 5249 case 4: /* tetradehdron */ 5250 *numFaceVertices = 3; /* Face has 3 vertices */ 5251 break; 5252 case 6: /* tet cohesive cells */ 5253 *numFaceVertices = 4; /* Face has 4 vertices */ 5254 break; 5255 case 8: /* hexahedron */ 5256 *numFaceVertices = 4; /* Face has 4 vertices */ 5257 break; 5258 case 9: /* tet cohesive Lagrange cells */ 5259 *numFaceVertices = 6; /* Face has 6 vertices */ 5260 break; 5261 case 10: /* quadratic tetrahedron */ 5262 *numFaceVertices = 6; /* Face has 6 vertices */ 5263 break; 5264 case 12: /* hex cohesive Lagrange cells */ 5265 *numFaceVertices = 6; /* Face has 6 vertices */ 5266 break; 5267 case 18: /* quadratic tet cohesive Lagrange cells */ 5268 *numFaceVertices = 6; /* Face has 6 vertices */ 5269 break; 5270 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5271 *numFaceVertices = 9; /* Face has 9 vertices */ 5272 break; 5273 default: 5274 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5275 } 5276 break; 5277 default: 5278 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5279 } 5280 PetscFunctionReturn(PETSC_SUCCESS); 5281 } 5282 5283 /*@ 5284 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5285 5286 Not Collective 5287 5288 Input Parameter: 5289 . dm - The `DMPLEX` object 5290 5291 Output Parameter: 5292 . depthLabel - The `DMLabel` recording point depth 5293 5294 Level: developer 5295 5296 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5297 @*/ 5298 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5299 { 5300 PetscFunctionBegin; 5301 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5302 PetscAssertPointer(depthLabel, 2); 5303 *depthLabel = dm->depthLabel; 5304 PetscFunctionReturn(PETSC_SUCCESS); 5305 } 5306 5307 /*@ 5308 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5309 5310 Not Collective 5311 5312 Input Parameter: 5313 . dm - The `DMPLEX` object 5314 5315 Output Parameter: 5316 . depth - The number of strata (breadth first levels) in the DAG 5317 5318 Level: developer 5319 5320 Notes: 5321 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5322 5323 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5324 5325 An empty mesh gives -1. 5326 5327 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5328 @*/ 5329 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5330 { 5331 DM_Plex *mesh = (DM_Plex *)dm->data; 5332 DMLabel label; 5333 PetscInt d = -1; 5334 5335 PetscFunctionBegin; 5336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5337 PetscAssertPointer(depth, 2); 5338 if (mesh->tr) { 5339 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5340 } else { 5341 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5342 // Allow missing depths 5343 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5344 *depth = d; 5345 } 5346 PetscFunctionReturn(PETSC_SUCCESS); 5347 } 5348 5349 /*@ 5350 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5351 5352 Not Collective 5353 5354 Input Parameters: 5355 + dm - The `DMPLEX` object 5356 - depth - The requested depth 5357 5358 Output Parameters: 5359 + start - The first point at this `depth` 5360 - end - One beyond the last point at this `depth` 5361 5362 Level: developer 5363 5364 Notes: 5365 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5366 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5367 higher dimension, e.g., "edges". 5368 5369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5370 @*/ 5371 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5372 { 5373 DM_Plex *mesh = (DM_Plex *)dm->data; 5374 DMLabel label; 5375 PetscInt pStart, pEnd; 5376 5377 PetscFunctionBegin; 5378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5379 if (start) { 5380 PetscAssertPointer(start, 3); 5381 *start = 0; 5382 } 5383 if (end) { 5384 PetscAssertPointer(end, 4); 5385 *end = 0; 5386 } 5387 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5388 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5389 if (depth < 0) { 5390 if (start) *start = pStart; 5391 if (end) *end = pEnd; 5392 PetscFunctionReturn(PETSC_SUCCESS); 5393 } 5394 if (mesh->tr) { 5395 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5396 } else { 5397 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5398 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5399 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5400 } 5401 PetscFunctionReturn(PETSC_SUCCESS); 5402 } 5403 5404 /*@ 5405 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5406 5407 Not Collective 5408 5409 Input Parameters: 5410 + dm - The `DMPLEX` object 5411 - height - The requested height 5412 5413 Output Parameters: 5414 + start - The first point at this `height` 5415 - end - One beyond the last point at this `height` 5416 5417 Level: developer 5418 5419 Notes: 5420 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5421 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5422 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5423 5424 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5425 @*/ 5426 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5427 { 5428 DMLabel label; 5429 PetscInt depth, pStart, pEnd; 5430 5431 PetscFunctionBegin; 5432 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5433 if (start) { 5434 PetscAssertPointer(start, 3); 5435 *start = 0; 5436 } 5437 if (end) { 5438 PetscAssertPointer(end, 4); 5439 *end = 0; 5440 } 5441 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5442 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5443 if (height < 0) { 5444 if (start) *start = pStart; 5445 if (end) *end = pEnd; 5446 PetscFunctionReturn(PETSC_SUCCESS); 5447 } 5448 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5449 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5450 else PetscCall(DMGetDimension(dm, &depth)); 5451 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5452 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5453 PetscFunctionReturn(PETSC_SUCCESS); 5454 } 5455 5456 /*@ 5457 DMPlexGetPointDepth - Get the `depth` of a given point 5458 5459 Not Collective 5460 5461 Input Parameters: 5462 + dm - The `DMPLEX` object 5463 - point - The point 5464 5465 Output Parameter: 5466 . depth - The depth of the `point` 5467 5468 Level: intermediate 5469 5470 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5471 @*/ 5472 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5473 { 5474 PetscFunctionBegin; 5475 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5476 PetscAssertPointer(depth, 3); 5477 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5478 PetscFunctionReturn(PETSC_SUCCESS); 5479 } 5480 5481 /*@ 5482 DMPlexGetPointHeight - Get the `height` of a given point 5483 5484 Not Collective 5485 5486 Input Parameters: 5487 + dm - The `DMPLEX` object 5488 - point - The point 5489 5490 Output Parameter: 5491 . height - The height of the `point` 5492 5493 Level: intermediate 5494 5495 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5496 @*/ 5497 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5498 { 5499 PetscInt n, pDepth; 5500 5501 PetscFunctionBegin; 5502 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5503 PetscAssertPointer(height, 3); 5504 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5505 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5506 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5507 PetscFunctionReturn(PETSC_SUCCESS); 5508 } 5509 5510 /*@ 5511 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5512 5513 Not Collective 5514 5515 Input Parameter: 5516 . dm - The `DMPLEX` object 5517 5518 Output Parameter: 5519 . celltypeLabel - The `DMLabel` recording cell polytope type 5520 5521 Level: developer 5522 5523 Note: 5524 This function will trigger automatica computation of cell types. This can be disabled by calling 5525 `DMCreateLabel`(dm, "celltype") beforehand. 5526 5527 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5528 @*/ 5529 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5530 { 5531 PetscFunctionBegin; 5532 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5533 PetscAssertPointer(celltypeLabel, 2); 5534 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5535 *celltypeLabel = dm->celltypeLabel; 5536 PetscFunctionReturn(PETSC_SUCCESS); 5537 } 5538 5539 /*@ 5540 DMPlexGetCellType - Get the polytope type of a given cell 5541 5542 Not Collective 5543 5544 Input Parameters: 5545 + dm - The `DMPLEX` object 5546 - cell - The cell 5547 5548 Output Parameter: 5549 . celltype - The polytope type of the cell 5550 5551 Level: intermediate 5552 5553 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5554 @*/ 5555 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5556 { 5557 DM_Plex *mesh = (DM_Plex *)dm->data; 5558 DMLabel label; 5559 PetscInt ct; 5560 5561 PetscFunctionBegin; 5562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5563 PetscAssertPointer(celltype, 3); 5564 if (mesh->tr) { 5565 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5566 } else { 5567 PetscInt pStart, pEnd; 5568 5569 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5570 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5571 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5572 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5573 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5574 for (PetscInt p = pStart; p < pEnd; p++) { 5575 PetscCall(DMLabelGetValue(label, p, &ct)); 5576 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5577 } 5578 } 5579 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5580 if (PetscDefined(USE_DEBUG)) { 5581 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5582 PetscCall(DMLabelGetValue(label, cell, &ct)); 5583 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5584 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5585 } 5586 } 5587 PetscFunctionReturn(PETSC_SUCCESS); 5588 } 5589 5590 /*@ 5591 DMPlexSetCellType - Set the polytope type of a given cell 5592 5593 Not Collective 5594 5595 Input Parameters: 5596 + dm - The `DMPLEX` object 5597 . cell - The cell 5598 - celltype - The polytope type of the cell 5599 5600 Level: advanced 5601 5602 Note: 5603 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5604 is executed. This function will override the computed type. However, if automatic classification will not succeed 5605 and a user wants to manually specify all types, the classification must be disabled by calling 5606 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5607 5608 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5609 @*/ 5610 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5611 { 5612 DM_Plex *mesh = (DM_Plex *)dm->data; 5613 DMLabel label; 5614 PetscInt pStart, pEnd; 5615 5616 PetscFunctionBegin; 5617 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5618 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5619 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5620 PetscCall(DMLabelSetValue(label, cell, celltype)); 5621 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5622 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5623 PetscFunctionReturn(PETSC_SUCCESS); 5624 } 5625 5626 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5627 { 5628 PetscSection section; 5629 PetscInt maxHeight; 5630 const char *prefix; 5631 5632 PetscFunctionBegin; 5633 PetscCall(DMClone(dm, cdm)); 5634 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5635 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5636 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5637 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5638 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5639 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5640 PetscCall(DMSetLocalSection(*cdm, section)); 5641 PetscCall(PetscSectionDestroy(§ion)); 5642 5643 PetscCall(DMSetNumFields(*cdm, 1)); 5644 PetscCall(DMCreateDS(*cdm)); 5645 (*cdm)->cloneOpts = PETSC_TRUE; 5646 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5647 PetscFunctionReturn(PETSC_SUCCESS); 5648 } 5649 5650 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5651 { 5652 Vec coordsLocal, cellCoordsLocal; 5653 DM coordsDM, cellCoordsDM; 5654 5655 PetscFunctionBegin; 5656 *field = NULL; 5657 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5658 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5659 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5660 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5661 if (coordsLocal && coordsDM) { 5662 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5663 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5664 } 5665 PetscFunctionReturn(PETSC_SUCCESS); 5666 } 5667 5668 /*@ 5669 DMPlexGetConeSection - Return a section which describes the layout of cone data 5670 5671 Not Collective 5672 5673 Input Parameter: 5674 . dm - The `DMPLEX` object 5675 5676 Output Parameter: 5677 . section - The `PetscSection` object 5678 5679 Level: developer 5680 5681 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5682 @*/ 5683 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5684 { 5685 DM_Plex *mesh = (DM_Plex *)dm->data; 5686 5687 PetscFunctionBegin; 5688 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5689 if (section) *section = mesh->coneSection; 5690 PetscFunctionReturn(PETSC_SUCCESS); 5691 } 5692 5693 /*@ 5694 DMPlexGetSupportSection - Return a section which describes the layout of support data 5695 5696 Not Collective 5697 5698 Input Parameter: 5699 . dm - The `DMPLEX` object 5700 5701 Output Parameter: 5702 . section - The `PetscSection` object 5703 5704 Level: developer 5705 5706 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5707 @*/ 5708 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5709 { 5710 DM_Plex *mesh = (DM_Plex *)dm->data; 5711 5712 PetscFunctionBegin; 5713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5714 if (section) *section = mesh->supportSection; 5715 PetscFunctionReturn(PETSC_SUCCESS); 5716 } 5717 5718 /*@C 5719 DMPlexGetCones - Return cone data 5720 5721 Not Collective 5722 5723 Input Parameter: 5724 . dm - The `DMPLEX` object 5725 5726 Output Parameter: 5727 . cones - The cone for each point 5728 5729 Level: developer 5730 5731 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5732 @*/ 5733 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5734 { 5735 DM_Plex *mesh = (DM_Plex *)dm->data; 5736 5737 PetscFunctionBegin; 5738 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5739 if (cones) *cones = mesh->cones; 5740 PetscFunctionReturn(PETSC_SUCCESS); 5741 } 5742 5743 /*@C 5744 DMPlexGetConeOrientations - Return cone orientation data 5745 5746 Not Collective 5747 5748 Input Parameter: 5749 . dm - The `DMPLEX` object 5750 5751 Output Parameter: 5752 . coneOrientations - The array of cone orientations for all points 5753 5754 Level: developer 5755 5756 Notes: 5757 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5758 as returned by `DMPlexGetConeOrientation()`. 5759 5760 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5761 5762 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5763 @*/ 5764 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5765 { 5766 DM_Plex *mesh = (DM_Plex *)dm->data; 5767 5768 PetscFunctionBegin; 5769 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5770 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5771 PetscFunctionReturn(PETSC_SUCCESS); 5772 } 5773 5774 /******************************** FEM Support **********************************/ 5775 5776 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5777 { 5778 PetscInt depth; 5779 5780 PetscFunctionBegin; 5781 PetscCall(DMPlexGetDepth(plex, &depth)); 5782 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5783 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5784 PetscFunctionReturn(PETSC_SUCCESS); 5785 } 5786 5787 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5788 { 5789 PetscInt depth; 5790 5791 PetscFunctionBegin; 5792 PetscCall(DMPlexGetDepth(plex, &depth)); 5793 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5794 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5795 PetscFunctionReturn(PETSC_SUCCESS); 5796 } 5797 5798 /* 5799 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5800 representing a line in the section. 5801 */ 5802 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5803 { 5804 PetscObject obj; 5805 PetscClassId id; 5806 PetscFE fe = NULL; 5807 5808 PetscFunctionBeginHot; 5809 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5810 PetscCall(DMGetField(dm, field, NULL, &obj)); 5811 PetscCall(PetscObjectGetClassId(obj, &id)); 5812 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5813 5814 if (!fe) { 5815 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5816 /* An order k SEM disc has k-1 dofs on an edge */ 5817 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5818 *k = *k / *Nc + 1; 5819 } else { 5820 PetscInt dual_space_size, dim; 5821 PetscDualSpace dsp; 5822 5823 PetscCall(DMGetDimension(dm, &dim)); 5824 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5825 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5826 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5827 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5828 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5829 } 5830 PetscFunctionReturn(PETSC_SUCCESS); 5831 } 5832 5833 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5834 { 5835 PetscFunctionBeginHot; 5836 if (tensor) { 5837 *dof = PetscPowInt(k + 1, dim); 5838 } else { 5839 switch (dim) { 5840 case 1: 5841 *dof = k + 1; 5842 break; 5843 case 2: 5844 *dof = ((k + 1) * (k + 2)) / 2; 5845 break; 5846 case 3: 5847 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5848 break; 5849 default: 5850 *dof = 0; 5851 } 5852 } 5853 PetscFunctionReturn(PETSC_SUCCESS); 5854 } 5855 5856 /*@ 5857 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5858 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5859 section provided (or the section of the `DM`). 5860 5861 Input Parameters: 5862 + dm - The `DM` 5863 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5864 - section - The `PetscSection` to reorder, or `NULL` for the default section 5865 5866 Example: 5867 A typical interpolated single-quad mesh might order points as 5868 .vb 5869 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5870 5871 v4 -- e6 -- v3 5872 | | 5873 e7 c0 e8 5874 | | 5875 v1 -- e5 -- v2 5876 .ve 5877 5878 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5879 dofs in the order of points, e.g., 5880 .vb 5881 c0 -> [0,1,2,3] 5882 v1 -> [4] 5883 ... 5884 e5 -> [8, 9] 5885 .ve 5886 5887 which corresponds to the dofs 5888 .vb 5889 6 10 11 7 5890 13 2 3 15 5891 12 0 1 14 5892 4 8 9 5 5893 .ve 5894 5895 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5896 .vb 5897 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5898 .ve 5899 5900 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5901 .vb 5902 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5903 .ve 5904 5905 Level: developer 5906 5907 Notes: 5908 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5909 degree of the basis. 5910 5911 This is required to run with libCEED. 5912 5913 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5914 @*/ 5915 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5916 { 5917 DMLabel label; 5918 PetscInt dim, depth = -1, eStart = -1, Nf; 5919 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5920 5921 PetscFunctionBegin; 5922 PetscCall(DMGetDimension(dm, &dim)); 5923 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5924 if (point < 0) { 5925 PetscInt sStart, sEnd; 5926 5927 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5928 point = sEnd - sStart ? sStart : point; 5929 } 5930 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5931 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5932 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5933 if (depth == 1) { 5934 eStart = point; 5935 } else if (depth == dim) { 5936 const PetscInt *cone; 5937 5938 PetscCall(DMPlexGetCone(dm, point, &cone)); 5939 if (dim == 2) eStart = cone[0]; 5940 else if (dim == 3) { 5941 const PetscInt *cone2; 5942 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5943 eStart = cone2[0]; 5944 } 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); 5945 } 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); 5946 5947 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5948 for (PetscInt d = 1; d <= dim; d++) { 5949 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5950 PetscInt *perm; 5951 5952 for (f = 0; f < Nf; ++f) { 5953 PetscInt dof; 5954 5955 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5956 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5957 if (!continuous && d < dim) continue; 5958 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5959 size += dof * Nc; 5960 } 5961 PetscCall(PetscMalloc1(size, &perm)); 5962 for (f = 0; f < Nf; ++f) { 5963 switch (d) { 5964 case 1: 5965 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5966 if (!continuous && d < dim) continue; 5967 /* 5968 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5969 We want [ vtx0; edge of length k-1; vtx1 ] 5970 */ 5971 if (continuous) { 5972 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5973 for (i = 0; i < k - 1; i++) 5974 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5975 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5976 foffset = offset; 5977 } else { 5978 PetscInt dof; 5979 5980 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5981 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5982 foffset = offset; 5983 } 5984 break; 5985 case 2: 5986 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5987 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5988 if (!continuous && d < dim) continue; 5989 /* The SEM order is 5990 5991 v_lb, {e_b}, v_rb, 5992 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5993 v_lt, reverse {e_t}, v_rt 5994 */ 5995 if (continuous) { 5996 const PetscInt of = 0; 5997 const PetscInt oeb = of + PetscSqr(k - 1); 5998 const PetscInt oer = oeb + (k - 1); 5999 const PetscInt oet = oer + (k - 1); 6000 const PetscInt oel = oet + (k - 1); 6001 const PetscInt ovlb = oel + (k - 1); 6002 const PetscInt ovrb = ovlb + 1; 6003 const PetscInt ovrt = ovrb + 1; 6004 const PetscInt ovlt = ovrt + 1; 6005 PetscInt o; 6006 6007 /* bottom */ 6008 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6009 for (o = oeb; o < oer; ++o) 6010 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6011 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6012 /* middle */ 6013 for (i = 0; i < k - 1; ++i) { 6014 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6015 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6016 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6017 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6018 } 6019 /* top */ 6020 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6021 for (o = oel - 1; o >= oet; --o) 6022 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6023 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6024 foffset = offset; 6025 } else { 6026 PetscInt dof; 6027 6028 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6029 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6030 foffset = offset; 6031 } 6032 break; 6033 case 3: 6034 /* The original hex closure is 6035 6036 {c, 6037 f_b, f_t, f_f, f_b, f_r, f_l, 6038 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6039 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6040 */ 6041 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6042 if (!continuous && d < dim) continue; 6043 /* The SEM order is 6044 Bottom Slice 6045 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6046 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6047 v_blb, {e_bb}, v_brb, 6048 6049 Middle Slice (j) 6050 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6051 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6052 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6053 6054 Top Slice 6055 v_tlf, {e_tf}, v_trf, 6056 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6057 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6058 */ 6059 if (continuous) { 6060 const PetscInt oc = 0; 6061 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6062 const PetscInt oft = ofb + PetscSqr(k - 1); 6063 const PetscInt off = oft + PetscSqr(k - 1); 6064 const PetscInt ofk = off + PetscSqr(k - 1); 6065 const PetscInt ofr = ofk + PetscSqr(k - 1); 6066 const PetscInt ofl = ofr + PetscSqr(k - 1); 6067 const PetscInt oebl = ofl + PetscSqr(k - 1); 6068 const PetscInt oebb = oebl + (k - 1); 6069 const PetscInt oebr = oebb + (k - 1); 6070 const PetscInt oebf = oebr + (k - 1); 6071 const PetscInt oetf = oebf + (k - 1); 6072 const PetscInt oetr = oetf + (k - 1); 6073 const PetscInt oetb = oetr + (k - 1); 6074 const PetscInt oetl = oetb + (k - 1); 6075 const PetscInt oerf = oetl + (k - 1); 6076 const PetscInt oelf = oerf + (k - 1); 6077 const PetscInt oelb = oelf + (k - 1); 6078 const PetscInt oerb = oelb + (k - 1); 6079 const PetscInt ovblf = oerb + (k - 1); 6080 const PetscInt ovblb = ovblf + 1; 6081 const PetscInt ovbrb = ovblb + 1; 6082 const PetscInt ovbrf = ovbrb + 1; 6083 const PetscInt ovtlf = ovbrf + 1; 6084 const PetscInt ovtrf = ovtlf + 1; 6085 const PetscInt ovtrb = ovtrf + 1; 6086 const PetscInt ovtlb = ovtrb + 1; 6087 PetscInt o, n; 6088 6089 /* Bottom Slice */ 6090 /* bottom */ 6091 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6092 for (o = oetf - 1; o >= oebf; --o) 6093 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6094 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6095 /* middle */ 6096 for (i = 0; i < k - 1; ++i) { 6097 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6098 for (n = 0; n < k - 1; ++n) { 6099 o = ofb + n * (k - 1) + i; 6100 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6101 } 6102 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6103 } 6104 /* top */ 6105 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6106 for (o = oebb; o < oebr; ++o) 6107 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6108 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6109 6110 /* Middle Slice */ 6111 for (j = 0; j < k - 1; ++j) { 6112 /* bottom */ 6113 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6114 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6115 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6116 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6117 /* middle */ 6118 for (i = 0; i < k - 1; ++i) { 6119 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6120 for (n = 0; n < k - 1; ++n) 6121 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6122 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6123 } 6124 /* top */ 6125 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6126 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6127 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6128 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6129 } 6130 6131 /* Top Slice */ 6132 /* bottom */ 6133 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6134 for (o = oetf; o < oetr; ++o) 6135 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6136 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6137 /* middle */ 6138 for (i = 0; i < k - 1; ++i) { 6139 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6140 for (n = 0; n < k - 1; ++n) 6141 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6142 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6143 } 6144 /* top */ 6145 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6146 for (o = oetl - 1; o >= oetb; --o) 6147 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6148 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6149 6150 foffset = offset; 6151 } else { 6152 PetscInt dof; 6153 6154 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6155 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6156 foffset = offset; 6157 } 6158 break; 6159 default: 6160 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6161 } 6162 } 6163 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6164 /* Check permutation */ 6165 { 6166 PetscInt *check; 6167 6168 PetscCall(PetscMalloc1(size, &check)); 6169 for (i = 0; i < size; ++i) { 6170 check[i] = -1; 6171 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6172 } 6173 for (i = 0; i < size; ++i) check[perm[i]] = i; 6174 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6175 PetscCall(PetscFree(check)); 6176 } 6177 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6178 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6179 PetscInt *loc_perm; 6180 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6181 for (PetscInt i = 0; i < size; i++) { 6182 loc_perm[i] = perm[i]; 6183 loc_perm[size + i] = size + perm[i]; 6184 } 6185 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6186 } 6187 } 6188 PetscFunctionReturn(PETSC_SUCCESS); 6189 } 6190 6191 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6192 { 6193 PetscDS prob; 6194 PetscInt depth, Nf, h; 6195 DMLabel label; 6196 6197 PetscFunctionBeginHot; 6198 PetscCall(DMGetDS(dm, &prob)); 6199 Nf = prob->Nf; 6200 label = dm->depthLabel; 6201 *dspace = NULL; 6202 if (field < Nf) { 6203 PetscObject disc = prob->disc[field]; 6204 6205 if (disc->classid == PETSCFE_CLASSID) { 6206 PetscDualSpace dsp; 6207 6208 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6209 PetscCall(DMLabelGetNumValues(label, &depth)); 6210 PetscCall(DMLabelGetValue(label, point, &h)); 6211 h = depth - 1 - h; 6212 if (h) { 6213 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6214 } else { 6215 *dspace = dsp; 6216 } 6217 } 6218 } 6219 PetscFunctionReturn(PETSC_SUCCESS); 6220 } 6221 6222 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6223 { 6224 PetscScalar *array; 6225 const PetscScalar *vArray; 6226 const PetscInt *cone, *coneO; 6227 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6228 6229 PetscFunctionBeginHot; 6230 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6231 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6232 PetscCall(DMPlexGetCone(dm, point, &cone)); 6233 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6234 if (!values || !*values) { 6235 if ((point >= pStart) && (point < pEnd)) { 6236 PetscInt dof; 6237 6238 PetscCall(PetscSectionGetDof(section, point, &dof)); 6239 size += dof; 6240 } 6241 for (p = 0; p < numPoints; ++p) { 6242 const PetscInt cp = cone[p]; 6243 PetscInt dof; 6244 6245 if ((cp < pStart) || (cp >= pEnd)) continue; 6246 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6247 size += dof; 6248 } 6249 if (!values) { 6250 if (csize) *csize = size; 6251 PetscFunctionReturn(PETSC_SUCCESS); 6252 } 6253 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6254 } else { 6255 array = *values; 6256 } 6257 size = 0; 6258 PetscCall(VecGetArrayRead(v, &vArray)); 6259 if ((point >= pStart) && (point < pEnd)) { 6260 PetscInt dof, off, d; 6261 const PetscScalar *varr; 6262 6263 PetscCall(PetscSectionGetDof(section, point, &dof)); 6264 PetscCall(PetscSectionGetOffset(section, point, &off)); 6265 varr = PetscSafePointerPlusOffset(vArray, off); 6266 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6267 size += dof; 6268 } 6269 for (p = 0; p < numPoints; ++p) { 6270 const PetscInt cp = cone[p]; 6271 PetscInt o = coneO[p]; 6272 PetscInt dof, off, d; 6273 const PetscScalar *varr; 6274 6275 if ((cp < pStart) || (cp >= pEnd)) continue; 6276 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6277 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6278 varr = PetscSafePointerPlusOffset(vArray, off); 6279 if (o >= 0) { 6280 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6281 } else { 6282 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6283 } 6284 size += dof; 6285 } 6286 PetscCall(VecRestoreArrayRead(v, &vArray)); 6287 if (!*values) { 6288 if (csize) *csize = size; 6289 *values = array; 6290 } else { 6291 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6292 *csize = size; 6293 } 6294 PetscFunctionReturn(PETSC_SUCCESS); 6295 } 6296 6297 /* Compress out points not in the section */ 6298 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6299 { 6300 const PetscInt np = *numPoints; 6301 PetscInt pStart, pEnd, p, q; 6302 6303 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6304 for (p = 0, q = 0; p < np; ++p) { 6305 const PetscInt r = points[p * 2]; 6306 if ((r >= pStart) && (r < pEnd)) { 6307 points[q * 2] = r; 6308 points[q * 2 + 1] = points[p * 2 + 1]; 6309 ++q; 6310 } 6311 } 6312 *numPoints = q; 6313 return PETSC_SUCCESS; 6314 } 6315 6316 /* Compressed closure does not apply closure permutation */ 6317 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6318 { 6319 const PetscInt *cla = NULL; 6320 PetscInt np, *pts = NULL; 6321 6322 PetscFunctionBeginHot; 6323 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6324 if (!ornt && *clPoints) { 6325 PetscInt dof, off; 6326 6327 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6328 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6329 PetscCall(ISGetIndices(*clPoints, &cla)); 6330 np = dof / 2; 6331 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6332 } else { 6333 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6334 PetscCall(CompressPoints_Private(section, &np, pts)); 6335 } 6336 *numPoints = np; 6337 *points = pts; 6338 *clp = cla; 6339 PetscFunctionReturn(PETSC_SUCCESS); 6340 } 6341 6342 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6343 { 6344 PetscFunctionBeginHot; 6345 if (!*clPoints) { 6346 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6347 } else { 6348 PetscCall(ISRestoreIndices(*clPoints, clp)); 6349 } 6350 *numPoints = 0; 6351 *points = NULL; 6352 *clSec = NULL; 6353 *clPoints = NULL; 6354 *clp = NULL; 6355 PetscFunctionReturn(PETSC_SUCCESS); 6356 } 6357 6358 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6359 { 6360 PetscInt offset = 0, p; 6361 const PetscInt **perms = NULL; 6362 const PetscScalar **flips = NULL; 6363 6364 PetscFunctionBeginHot; 6365 *size = 0; 6366 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6367 for (p = 0; p < numPoints; p++) { 6368 const PetscInt point = points[2 * p]; 6369 const PetscInt *perm = perms ? perms[p] : NULL; 6370 const PetscScalar *flip = flips ? flips[p] : NULL; 6371 PetscInt dof, off, d; 6372 const PetscScalar *varr; 6373 6374 PetscCall(PetscSectionGetDof(section, point, &dof)); 6375 PetscCall(PetscSectionGetOffset(section, point, &off)); 6376 varr = PetscSafePointerPlusOffset(vArray, off); 6377 if (clperm) { 6378 if (perm) { 6379 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6380 } else { 6381 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6382 } 6383 if (flip) { 6384 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6385 } 6386 } else { 6387 if (perm) { 6388 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6389 } else { 6390 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6391 } 6392 if (flip) { 6393 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6394 } 6395 } 6396 offset += dof; 6397 } 6398 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6399 *size = offset; 6400 PetscFunctionReturn(PETSC_SUCCESS); 6401 } 6402 6403 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[]) 6404 { 6405 PetscInt offset = 0, f; 6406 6407 PetscFunctionBeginHot; 6408 *size = 0; 6409 for (f = 0; f < numFields; ++f) { 6410 PetscInt p; 6411 const PetscInt **perms = NULL; 6412 const PetscScalar **flips = NULL; 6413 6414 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6415 for (p = 0; p < numPoints; p++) { 6416 const PetscInt point = points[2 * p]; 6417 PetscInt fdof, foff, b; 6418 const PetscScalar *varr; 6419 const PetscInt *perm = perms ? perms[p] : NULL; 6420 const PetscScalar *flip = flips ? flips[p] : NULL; 6421 6422 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6423 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6424 varr = &vArray[foff]; 6425 if (clperm) { 6426 if (perm) { 6427 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6428 } else { 6429 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6430 } 6431 if (flip) { 6432 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6433 } 6434 } else { 6435 if (perm) { 6436 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6437 } else { 6438 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6439 } 6440 if (flip) { 6441 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6442 } 6443 } 6444 offset += fdof; 6445 } 6446 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6447 } 6448 *size = offset; 6449 PetscFunctionReturn(PETSC_SUCCESS); 6450 } 6451 6452 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6453 { 6454 PetscSection clSection; 6455 IS clPoints; 6456 PetscInt *points = NULL; 6457 const PetscInt *clp, *perm = NULL; 6458 PetscInt depth, numFields, numPoints, asize; 6459 6460 PetscFunctionBeginHot; 6461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6462 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6463 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6464 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6465 PetscCall(DMPlexGetDepth(dm, &depth)); 6466 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6467 if (depth == 1 && numFields < 2) { 6468 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6469 PetscFunctionReturn(PETSC_SUCCESS); 6470 } 6471 /* Get points */ 6472 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6473 /* Get sizes */ 6474 asize = 0; 6475 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6476 PetscInt dof; 6477 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6478 asize += dof; 6479 } 6480 if (values) { 6481 const PetscScalar *vArray; 6482 PetscInt size; 6483 6484 if (*values) { 6485 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); 6486 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6487 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6488 PetscCall(VecGetArrayRead(v, &vArray)); 6489 /* Get values */ 6490 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6491 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6492 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6493 /* Cleanup array */ 6494 PetscCall(VecRestoreArrayRead(v, &vArray)); 6495 } 6496 if (csize) *csize = asize; 6497 /* Cleanup points */ 6498 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6499 PetscFunctionReturn(PETSC_SUCCESS); 6500 } 6501 6502 /*@C 6503 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6504 6505 Not collective 6506 6507 Input Parameters: 6508 + dm - The `DM` 6509 . section - The section describing the layout in `v`, or `NULL` to use the default section 6510 . v - The local vector 6511 - point - The point in the `DM` 6512 6513 Input/Output Parameters: 6514 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6515 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6516 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6517 6518 Level: intermediate 6519 6520 Notes: 6521 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6522 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6523 assembly function, and a user may already have allocated storage for this operation. 6524 6525 A typical use could be 6526 .vb 6527 values = NULL; 6528 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6529 for (cl = 0; cl < clSize; ++cl) { 6530 <Compute on closure> 6531 } 6532 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6533 .ve 6534 or 6535 .vb 6536 PetscMalloc1(clMaxSize, &values); 6537 for (p = pStart; p < pEnd; ++p) { 6538 clSize = clMaxSize; 6539 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6540 for (cl = 0; cl < clSize; ++cl) { 6541 <Compute on closure> 6542 } 6543 } 6544 PetscFree(values); 6545 .ve 6546 6547 Fortran Notes: 6548 The `csize` argument is not present in the Fortran binding. 6549 6550 `values` must be declared with 6551 .vb 6552 PetscScalar,dimension(:),pointer :: values 6553 .ve 6554 and it will be allocated internally by PETSc to hold the values returned 6555 6556 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6557 @*/ 6558 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6559 { 6560 PetscFunctionBeginHot; 6561 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6562 PetscFunctionReturn(PETSC_SUCCESS); 6563 } 6564 6565 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6566 { 6567 DMLabel depthLabel; 6568 PetscSection clSection; 6569 IS clPoints; 6570 PetscScalar *array; 6571 const PetscScalar *vArray; 6572 PetscInt *points = NULL; 6573 const PetscInt *clp, *perm = NULL; 6574 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6575 6576 PetscFunctionBeginHot; 6577 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6578 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6579 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6580 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6581 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6582 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6583 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6584 if (mdepth == 1 && numFields < 2) { 6585 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6586 PetscFunctionReturn(PETSC_SUCCESS); 6587 } 6588 /* Get points */ 6589 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6590 for (clsize = 0, p = 0; p < Np; p++) { 6591 PetscInt dof; 6592 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6593 clsize += dof; 6594 } 6595 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6596 /* Filter points */ 6597 for (p = 0; p < numPoints * 2; p += 2) { 6598 PetscInt dep; 6599 6600 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6601 if (dep != depth) continue; 6602 points[Np * 2 + 0] = points[p]; 6603 points[Np * 2 + 1] = points[p + 1]; 6604 ++Np; 6605 } 6606 /* Get array */ 6607 if (!values || !*values) { 6608 PetscInt asize = 0, dof; 6609 6610 for (p = 0; p < Np * 2; p += 2) { 6611 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6612 asize += dof; 6613 } 6614 if (!values) { 6615 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6616 if (csize) *csize = asize; 6617 PetscFunctionReturn(PETSC_SUCCESS); 6618 } 6619 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6620 } else { 6621 array = *values; 6622 } 6623 PetscCall(VecGetArrayRead(v, &vArray)); 6624 /* Get values */ 6625 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6626 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6627 /* Cleanup points */ 6628 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6629 /* Cleanup array */ 6630 PetscCall(VecRestoreArrayRead(v, &vArray)); 6631 if (!*values) { 6632 if (csize) *csize = size; 6633 *values = array; 6634 } else { 6635 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6636 *csize = size; 6637 } 6638 PetscFunctionReturn(PETSC_SUCCESS); 6639 } 6640 6641 /*@C 6642 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6643 6644 Not collective 6645 6646 Input Parameters: 6647 + dm - The `DM` 6648 . section - The section describing the layout in `v`, or `NULL` to use the default section 6649 . v - The local vector 6650 . point - The point in the `DM` 6651 . csize - The number of values in the closure, or `NULL` 6652 - values - The array of values 6653 6654 Level: intermediate 6655 6656 Note: 6657 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6658 6659 Fortran Note: 6660 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6661 6662 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6663 @*/ 6664 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6665 { 6666 PetscInt size = 0; 6667 6668 PetscFunctionBegin; 6669 /* Should work without recalculating size */ 6670 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6671 *values = NULL; 6672 PetscFunctionReturn(PETSC_SUCCESS); 6673 } 6674 6675 static inline void add(PetscScalar *x, PetscScalar y) 6676 { 6677 *x += y; 6678 } 6679 static inline void insert(PetscScalar *x, PetscScalar y) 6680 { 6681 *x = y; 6682 } 6683 6684 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[]) 6685 { 6686 PetscInt cdof; /* The number of constraints on this point */ 6687 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6688 PetscScalar *a; 6689 PetscInt off, cind = 0, k; 6690 6691 PetscFunctionBegin; 6692 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6693 PetscCall(PetscSectionGetOffset(section, point, &off)); 6694 a = &array[off]; 6695 if (!cdof || setBC) { 6696 if (clperm) { 6697 if (perm) { 6698 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6699 } else { 6700 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6701 } 6702 } else { 6703 if (perm) { 6704 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6705 } else { 6706 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6707 } 6708 } 6709 } else { 6710 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6711 if (clperm) { 6712 if (perm) { 6713 for (k = 0; k < dof; ++k) { 6714 if ((cind < cdof) && (k == cdofs[cind])) { 6715 ++cind; 6716 continue; 6717 } 6718 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6719 } 6720 } else { 6721 for (k = 0; k < dof; ++k) { 6722 if ((cind < cdof) && (k == cdofs[cind])) { 6723 ++cind; 6724 continue; 6725 } 6726 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6727 } 6728 } 6729 } else { 6730 if (perm) { 6731 for (k = 0; k < dof; ++k) { 6732 if ((cind < cdof) && (k == cdofs[cind])) { 6733 ++cind; 6734 continue; 6735 } 6736 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6737 } 6738 } else { 6739 for (k = 0; k < dof; ++k) { 6740 if ((cind < cdof) && (k == cdofs[cind])) { 6741 ++cind; 6742 continue; 6743 } 6744 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6745 } 6746 } 6747 } 6748 } 6749 PetscFunctionReturn(PETSC_SUCCESS); 6750 } 6751 6752 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[]) 6753 { 6754 PetscInt cdof; /* The number of constraints on this point */ 6755 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6756 PetscScalar *a; 6757 PetscInt off, cind = 0, k; 6758 6759 PetscFunctionBegin; 6760 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6761 PetscCall(PetscSectionGetOffset(section, point, &off)); 6762 a = &array[off]; 6763 if (cdof) { 6764 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6765 if (clperm) { 6766 if (perm) { 6767 for (k = 0; k < dof; ++k) { 6768 if ((cind < cdof) && (k == cdofs[cind])) { 6769 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6770 cind++; 6771 } 6772 } 6773 } else { 6774 for (k = 0; k < dof; ++k) { 6775 if ((cind < cdof) && (k == cdofs[cind])) { 6776 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6777 cind++; 6778 } 6779 } 6780 } 6781 } else { 6782 if (perm) { 6783 for (k = 0; k < dof; ++k) { 6784 if ((cind < cdof) && (k == cdofs[cind])) { 6785 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6786 cind++; 6787 } 6788 } 6789 } else { 6790 for (k = 0; k < dof; ++k) { 6791 if ((cind < cdof) && (k == cdofs[cind])) { 6792 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6793 cind++; 6794 } 6795 } 6796 } 6797 } 6798 } 6799 PetscFunctionReturn(PETSC_SUCCESS); 6800 } 6801 6802 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[]) 6803 { 6804 PetscScalar *a; 6805 PetscInt fdof, foff, fcdof, foffset = *offset; 6806 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6807 PetscInt cind = 0, b; 6808 6809 PetscFunctionBegin; 6810 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6811 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6812 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6813 a = &array[foff]; 6814 if (!fcdof || setBC) { 6815 if (clperm) { 6816 if (perm) { 6817 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6818 } else { 6819 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6820 } 6821 } else { 6822 if (perm) { 6823 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6824 } else { 6825 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6826 } 6827 } 6828 } else { 6829 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6830 if (clperm) { 6831 if (perm) { 6832 for (b = 0; b < fdof; b++) { 6833 if ((cind < fcdof) && (b == fcdofs[cind])) { 6834 ++cind; 6835 continue; 6836 } 6837 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6838 } 6839 } else { 6840 for (b = 0; b < fdof; b++) { 6841 if ((cind < fcdof) && (b == fcdofs[cind])) { 6842 ++cind; 6843 continue; 6844 } 6845 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6846 } 6847 } 6848 } else { 6849 if (perm) { 6850 for (b = 0; b < fdof; b++) { 6851 if ((cind < fcdof) && (b == fcdofs[cind])) { 6852 ++cind; 6853 continue; 6854 } 6855 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6856 } 6857 } else { 6858 for (b = 0; b < fdof; b++) { 6859 if ((cind < fcdof) && (b == fcdofs[cind])) { 6860 ++cind; 6861 continue; 6862 } 6863 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6864 } 6865 } 6866 } 6867 } 6868 *offset += fdof; 6869 PetscFunctionReturn(PETSC_SUCCESS); 6870 } 6871 6872 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[]) 6873 { 6874 PetscScalar *a; 6875 PetscInt fdof, foff, fcdof, foffset = *offset; 6876 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6877 PetscInt Nc, cind = 0, ncind = 0, b; 6878 PetscBool ncSet, fcSet; 6879 6880 PetscFunctionBegin; 6881 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6882 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6883 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6884 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6885 a = &array[foff]; 6886 if (fcdof) { 6887 /* We just override fcdof and fcdofs with Ncc and comps */ 6888 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6889 if (clperm) { 6890 if (perm) { 6891 if (comps) { 6892 for (b = 0; b < fdof; b++) { 6893 ncSet = fcSet = PETSC_FALSE; 6894 if (b % Nc == comps[ncind]) { 6895 ncind = (ncind + 1) % Ncc; 6896 ncSet = PETSC_TRUE; 6897 } 6898 if ((cind < fcdof) && (b == fcdofs[cind])) { 6899 ++cind; 6900 fcSet = PETSC_TRUE; 6901 } 6902 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6903 } 6904 } else { 6905 for (b = 0; b < fdof; b++) { 6906 if ((cind < fcdof) && (b == fcdofs[cind])) { 6907 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6908 ++cind; 6909 } 6910 } 6911 } 6912 } else { 6913 if (comps) { 6914 for (b = 0; b < fdof; b++) { 6915 ncSet = fcSet = PETSC_FALSE; 6916 if (b % Nc == comps[ncind]) { 6917 ncind = (ncind + 1) % Ncc; 6918 ncSet = PETSC_TRUE; 6919 } 6920 if ((cind < fcdof) && (b == fcdofs[cind])) { 6921 ++cind; 6922 fcSet = PETSC_TRUE; 6923 } 6924 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6925 } 6926 } else { 6927 for (b = 0; b < fdof; b++) { 6928 if ((cind < fcdof) && (b == fcdofs[cind])) { 6929 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6930 ++cind; 6931 } 6932 } 6933 } 6934 } 6935 } else { 6936 if (perm) { 6937 if (comps) { 6938 for (b = 0; b < fdof; b++) { 6939 ncSet = fcSet = PETSC_FALSE; 6940 if (b % Nc == comps[ncind]) { 6941 ncind = (ncind + 1) % Ncc; 6942 ncSet = PETSC_TRUE; 6943 } 6944 if ((cind < fcdof) && (b == fcdofs[cind])) { 6945 ++cind; 6946 fcSet = PETSC_TRUE; 6947 } 6948 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6949 } 6950 } else { 6951 for (b = 0; b < fdof; b++) { 6952 if ((cind < fcdof) && (b == fcdofs[cind])) { 6953 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6954 ++cind; 6955 } 6956 } 6957 } 6958 } else { 6959 if (comps) { 6960 for (b = 0; b < fdof; b++) { 6961 ncSet = fcSet = PETSC_FALSE; 6962 if (b % Nc == comps[ncind]) { 6963 ncind = (ncind + 1) % Ncc; 6964 ncSet = PETSC_TRUE; 6965 } 6966 if ((cind < fcdof) && (b == fcdofs[cind])) { 6967 ++cind; 6968 fcSet = PETSC_TRUE; 6969 } 6970 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6971 } 6972 } else { 6973 for (b = 0; b < fdof; b++) { 6974 if ((cind < fcdof) && (b == fcdofs[cind])) { 6975 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6976 ++cind; 6977 } 6978 } 6979 } 6980 } 6981 } 6982 } 6983 *offset += fdof; 6984 PetscFunctionReturn(PETSC_SUCCESS); 6985 } 6986 6987 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6988 { 6989 PetscScalar *array; 6990 const PetscInt *cone, *coneO; 6991 PetscInt pStart, pEnd, p, numPoints, off, dof; 6992 6993 PetscFunctionBeginHot; 6994 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6995 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6996 PetscCall(DMPlexGetCone(dm, point, &cone)); 6997 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6998 PetscCall(VecGetArray(v, &array)); 6999 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7000 const PetscInt cp = !p ? point : cone[p - 1]; 7001 const PetscInt o = !p ? 0 : coneO[p - 1]; 7002 7003 if ((cp < pStart) || (cp >= pEnd)) { 7004 dof = 0; 7005 continue; 7006 } 7007 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7008 /* ADD_VALUES */ 7009 { 7010 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7011 PetscScalar *a; 7012 PetscInt cdof, coff, cind = 0, k; 7013 7014 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7015 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7016 a = &array[coff]; 7017 if (!cdof) { 7018 if (o >= 0) { 7019 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7020 } else { 7021 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7022 } 7023 } else { 7024 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7025 if (o >= 0) { 7026 for (k = 0; k < dof; ++k) { 7027 if ((cind < cdof) && (k == cdofs[cind])) { 7028 ++cind; 7029 continue; 7030 } 7031 a[k] += values[off + k]; 7032 } 7033 } else { 7034 for (k = 0; k < dof; ++k) { 7035 if ((cind < cdof) && (k == cdofs[cind])) { 7036 ++cind; 7037 continue; 7038 } 7039 a[k] += values[off + dof - k - 1]; 7040 } 7041 } 7042 } 7043 } 7044 } 7045 PetscCall(VecRestoreArray(v, &array)); 7046 PetscFunctionReturn(PETSC_SUCCESS); 7047 } 7048 7049 /*@C 7050 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7051 7052 Not collective 7053 7054 Input Parameters: 7055 + dm - The `DM` 7056 . section - The section describing the layout in `v`, or `NULL` to use the default section 7057 . v - The local vector 7058 . point - The point in the `DM` 7059 . values - The array of values 7060 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7061 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7062 7063 Level: intermediate 7064 7065 Note: 7066 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7067 7068 Fortran Note: 7069 `values` must be declared with 7070 .vb 7071 PetscScalar,dimension(:),pointer :: values 7072 .ve 7073 7074 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7075 @*/ 7076 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7077 { 7078 PetscSection clSection; 7079 IS clPoints; 7080 PetscScalar *array; 7081 PetscInt *points = NULL; 7082 const PetscInt *clp, *clperm = NULL; 7083 PetscInt depth, numFields, numPoints, p, clsize; 7084 7085 PetscFunctionBeginHot; 7086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7087 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7088 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7089 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7090 PetscCall(DMPlexGetDepth(dm, &depth)); 7091 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7092 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7093 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7094 PetscFunctionReturn(PETSC_SUCCESS); 7095 } 7096 /* Get points */ 7097 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7098 for (clsize = 0, p = 0; p < numPoints; p++) { 7099 PetscInt dof; 7100 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7101 clsize += dof; 7102 } 7103 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7104 /* Get array */ 7105 PetscCall(VecGetArray(v, &array)); 7106 /* Get values */ 7107 if (numFields > 0) { 7108 PetscInt offset = 0, f; 7109 for (f = 0; f < numFields; ++f) { 7110 const PetscInt **perms = NULL; 7111 const PetscScalar **flips = NULL; 7112 7113 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7114 switch (mode) { 7115 case INSERT_VALUES: 7116 for (p = 0; p < numPoints; p++) { 7117 const PetscInt point = points[2 * p]; 7118 const PetscInt *perm = perms ? perms[p] : NULL; 7119 const PetscScalar *flip = flips ? flips[p] : NULL; 7120 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7121 } 7122 break; 7123 case INSERT_ALL_VALUES: 7124 for (p = 0; p < numPoints; p++) { 7125 const PetscInt point = points[2 * p]; 7126 const PetscInt *perm = perms ? perms[p] : NULL; 7127 const PetscScalar *flip = flips ? flips[p] : NULL; 7128 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7129 } 7130 break; 7131 case INSERT_BC_VALUES: 7132 for (p = 0; p < numPoints; p++) { 7133 const PetscInt point = points[2 * p]; 7134 const PetscInt *perm = perms ? perms[p] : NULL; 7135 const PetscScalar *flip = flips ? flips[p] : NULL; 7136 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7137 } 7138 break; 7139 case ADD_VALUES: 7140 for (p = 0; p < numPoints; p++) { 7141 const PetscInt point = points[2 * p]; 7142 const PetscInt *perm = perms ? perms[p] : NULL; 7143 const PetscScalar *flip = flips ? flips[p] : NULL; 7144 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7145 } 7146 break; 7147 case ADD_ALL_VALUES: 7148 for (p = 0; p < numPoints; p++) { 7149 const PetscInt point = points[2 * p]; 7150 const PetscInt *perm = perms ? perms[p] : NULL; 7151 const PetscScalar *flip = flips ? flips[p] : NULL; 7152 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7153 } 7154 break; 7155 case ADD_BC_VALUES: 7156 for (p = 0; p < numPoints; p++) { 7157 const PetscInt point = points[2 * p]; 7158 const PetscInt *perm = perms ? perms[p] : NULL; 7159 const PetscScalar *flip = flips ? flips[p] : NULL; 7160 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7161 } 7162 break; 7163 default: 7164 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7165 } 7166 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7167 } 7168 } else { 7169 PetscInt dof, off; 7170 const PetscInt **perms = NULL; 7171 const PetscScalar **flips = NULL; 7172 7173 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7174 switch (mode) { 7175 case INSERT_VALUES: 7176 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7177 const PetscInt point = points[2 * p]; 7178 const PetscInt *perm = perms ? perms[p] : NULL; 7179 const PetscScalar *flip = flips ? flips[p] : NULL; 7180 PetscCall(PetscSectionGetDof(section, point, &dof)); 7181 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7182 } 7183 break; 7184 case INSERT_ALL_VALUES: 7185 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7186 const PetscInt point = points[2 * p]; 7187 const PetscInt *perm = perms ? perms[p] : NULL; 7188 const PetscScalar *flip = flips ? flips[p] : NULL; 7189 PetscCall(PetscSectionGetDof(section, point, &dof)); 7190 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7191 } 7192 break; 7193 case INSERT_BC_VALUES: 7194 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 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(PetscSectionGetDof(section, point, &dof)); 7199 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7200 } 7201 break; 7202 case ADD_VALUES: 7203 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7204 const PetscInt point = points[2 * p]; 7205 const PetscInt *perm = perms ? perms[p] : NULL; 7206 const PetscScalar *flip = flips ? flips[p] : NULL; 7207 PetscCall(PetscSectionGetDof(section, point, &dof)); 7208 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7209 } 7210 break; 7211 case ADD_ALL_VALUES: 7212 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7213 const PetscInt point = points[2 * p]; 7214 const PetscInt *perm = perms ? perms[p] : NULL; 7215 const PetscScalar *flip = flips ? flips[p] : NULL; 7216 PetscCall(PetscSectionGetDof(section, point, &dof)); 7217 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7218 } 7219 break; 7220 case ADD_BC_VALUES: 7221 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7222 const PetscInt point = points[2 * p]; 7223 const PetscInt *perm = perms ? perms[p] : NULL; 7224 const PetscScalar *flip = flips ? flips[p] : NULL; 7225 PetscCall(PetscSectionGetDof(section, point, &dof)); 7226 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7227 } 7228 break; 7229 default: 7230 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7231 } 7232 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7233 } 7234 /* Cleanup points */ 7235 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7236 /* Cleanup array */ 7237 PetscCall(VecRestoreArray(v, &array)); 7238 PetscFunctionReturn(PETSC_SUCCESS); 7239 } 7240 7241 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7242 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7243 { 7244 PetscFunctionBegin; 7245 *contains = PETSC_TRUE; 7246 if (label) { 7247 PetscInt fdof; 7248 7249 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7250 if (!*contains) { 7251 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7252 *offset += fdof; 7253 PetscFunctionReturn(PETSC_SUCCESS); 7254 } 7255 } 7256 PetscFunctionReturn(PETSC_SUCCESS); 7257 } 7258 7259 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7260 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) 7261 { 7262 PetscSection clSection; 7263 IS clPoints; 7264 PetscScalar *array; 7265 PetscInt *points = NULL; 7266 const PetscInt *clp; 7267 PetscInt numFields, numPoints, p; 7268 PetscInt offset = 0, f; 7269 7270 PetscFunctionBeginHot; 7271 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7272 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7273 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7274 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7275 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7276 /* Get points */ 7277 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7278 /* Get array */ 7279 PetscCall(VecGetArray(v, &array)); 7280 /* Get values */ 7281 for (f = 0; f < numFields; ++f) { 7282 const PetscInt **perms = NULL; 7283 const PetscScalar **flips = NULL; 7284 PetscBool contains; 7285 7286 if (!fieldActive[f]) { 7287 for (p = 0; p < numPoints * 2; p += 2) { 7288 PetscInt fdof; 7289 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7290 offset += fdof; 7291 } 7292 continue; 7293 } 7294 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7295 switch (mode) { 7296 case INSERT_VALUES: 7297 for (p = 0; p < numPoints; p++) { 7298 const PetscInt point = points[2 * p]; 7299 const PetscInt *perm = perms ? perms[p] : NULL; 7300 const PetscScalar *flip = flips ? flips[p] : NULL; 7301 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7302 if (!contains) continue; 7303 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7304 } 7305 break; 7306 case INSERT_ALL_VALUES: 7307 for (p = 0; p < numPoints; p++) { 7308 const PetscInt point = points[2 * p]; 7309 const PetscInt *perm = perms ? perms[p] : NULL; 7310 const PetscScalar *flip = flips ? flips[p] : NULL; 7311 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7312 if (!contains) continue; 7313 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7314 } 7315 break; 7316 case INSERT_BC_VALUES: 7317 for (p = 0; p < numPoints; p++) { 7318 const PetscInt point = points[2 * p]; 7319 const PetscInt *perm = perms ? perms[p] : NULL; 7320 const PetscScalar *flip = flips ? flips[p] : NULL; 7321 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7322 if (!contains) continue; 7323 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7324 } 7325 break; 7326 case ADD_VALUES: 7327 for (p = 0; p < numPoints; p++) { 7328 const PetscInt point = points[2 * p]; 7329 const PetscInt *perm = perms ? perms[p] : NULL; 7330 const PetscScalar *flip = flips ? flips[p] : NULL; 7331 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7332 if (!contains) continue; 7333 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7334 } 7335 break; 7336 case ADD_ALL_VALUES: 7337 for (p = 0; p < numPoints; p++) { 7338 const PetscInt point = points[2 * p]; 7339 const PetscInt *perm = perms ? perms[p] : NULL; 7340 const PetscScalar *flip = flips ? flips[p] : NULL; 7341 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7342 if (!contains) continue; 7343 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7344 } 7345 break; 7346 default: 7347 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7348 } 7349 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7350 } 7351 /* Cleanup points */ 7352 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7353 /* Cleanup array */ 7354 PetscCall(VecRestoreArray(v, &array)); 7355 PetscFunctionReturn(PETSC_SUCCESS); 7356 } 7357 7358 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7359 { 7360 PetscMPIInt rank; 7361 PetscInt i, j; 7362 7363 PetscFunctionBegin; 7364 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7365 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7366 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7367 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7368 numCIndices = numCIndices ? numCIndices : numRIndices; 7369 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7370 for (i = 0; i < numRIndices; i++) { 7371 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7372 for (j = 0; j < numCIndices; j++) { 7373 #if defined(PETSC_USE_COMPLEX) 7374 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7375 #else 7376 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7377 #endif 7378 } 7379 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7380 } 7381 PetscFunctionReturn(PETSC_SUCCESS); 7382 } 7383 7384 /* 7385 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7386 7387 Input Parameters: 7388 + section - The section for this data layout 7389 . islocal - Is the section (and thus indices being requested) local or global? 7390 . point - The point contributing dofs with these indices 7391 . off - The global offset of this point 7392 . loff - The local offset of each field 7393 . setBC - The flag determining whether to include indices of boundary values 7394 . perm - A permutation of the dofs on this point, or NULL 7395 - indperm - A permutation of the entire indices array, or NULL 7396 7397 Output Parameter: 7398 . indices - Indices for dofs on this point 7399 7400 Level: developer 7401 7402 Note: The indices could be local or global, depending on the value of 'off'. 7403 */ 7404 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7405 { 7406 PetscInt dof; /* The number of unknowns on this point */ 7407 PetscInt cdof; /* The number of constraints on this point */ 7408 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7409 PetscInt cind = 0, k; 7410 7411 PetscFunctionBegin; 7412 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7413 PetscCall(PetscSectionGetDof(section, point, &dof)); 7414 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7415 if (!cdof || setBC) { 7416 for (k = 0; k < dof; ++k) { 7417 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7418 const PetscInt ind = indperm ? indperm[preind] : preind; 7419 7420 indices[ind] = off + k; 7421 } 7422 } else { 7423 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7424 for (k = 0; k < dof; ++k) { 7425 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7426 const PetscInt ind = indperm ? indperm[preind] : preind; 7427 7428 if ((cind < cdof) && (k == cdofs[cind])) { 7429 /* Insert check for returning constrained indices */ 7430 indices[ind] = -(off + k + 1); 7431 ++cind; 7432 } else { 7433 indices[ind] = off + k - (islocal ? 0 : cind); 7434 } 7435 } 7436 } 7437 *loff += dof; 7438 PetscFunctionReturn(PETSC_SUCCESS); 7439 } 7440 7441 /* 7442 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7443 7444 Input Parameters: 7445 + section - a section (global or local) 7446 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7447 . point - point within section 7448 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7449 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7450 . setBC - identify constrained (boundary condition) points via involution. 7451 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7452 . permsoff - offset 7453 - indperm - index permutation 7454 7455 Output Parameter: 7456 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7457 . indices - array to hold indices (as defined by section) of each dof associated with point 7458 7459 Notes: 7460 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7461 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7462 in the local vector. 7463 7464 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7465 significant). It is invalid to call with a global section and setBC=true. 7466 7467 Developer Note: 7468 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7469 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7470 offset could be obtained from the section instead of passing it explicitly as we do now. 7471 7472 Example: 7473 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7474 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7475 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7476 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. 7477 7478 Level: developer 7479 */ 7480 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[]) 7481 { 7482 PetscInt numFields, foff, f; 7483 7484 PetscFunctionBegin; 7485 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7486 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7487 for (f = 0, foff = 0; f < numFields; ++f) { 7488 PetscInt fdof, cfdof; 7489 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7490 PetscInt cind = 0, b; 7491 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7492 7493 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7494 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7495 if (!cfdof || setBC) { 7496 for (b = 0; b < fdof; ++b) { 7497 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7498 const PetscInt ind = indperm ? indperm[preind] : preind; 7499 7500 indices[ind] = off + foff + b; 7501 } 7502 } else { 7503 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7504 for (b = 0; b < fdof; ++b) { 7505 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7506 const PetscInt ind = indperm ? indperm[preind] : preind; 7507 7508 if ((cind < cfdof) && (b == fcdofs[cind])) { 7509 indices[ind] = -(off + foff + b + 1); 7510 ++cind; 7511 } else { 7512 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7513 } 7514 } 7515 } 7516 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7517 foffs[f] += fdof; 7518 } 7519 PetscFunctionReturn(PETSC_SUCCESS); 7520 } 7521 7522 /* 7523 This version believes the globalSection offsets for each field, rather than just the point offset 7524 7525 . foffs - The offset into 'indices' for each field, since it is segregated by field 7526 7527 Notes: 7528 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7529 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7530 */ 7531 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7532 { 7533 PetscInt numFields, foff, f; 7534 7535 PetscFunctionBegin; 7536 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7537 for (f = 0; f < numFields; ++f) { 7538 PetscInt fdof, cfdof; 7539 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7540 PetscInt cind = 0, b; 7541 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7542 7543 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7544 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7545 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7546 if (!cfdof) { 7547 for (b = 0; b < fdof; ++b) { 7548 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7549 const PetscInt ind = indperm ? indperm[preind] : preind; 7550 7551 indices[ind] = foff + b; 7552 } 7553 } else { 7554 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7555 for (b = 0; b < fdof; ++b) { 7556 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7557 const PetscInt ind = indperm ? indperm[preind] : preind; 7558 7559 if ((cind < cfdof) && (b == fcdofs[cind])) { 7560 indices[ind] = -(foff + b + 1); 7561 ++cind; 7562 } else { 7563 indices[ind] = foff + b - cind; 7564 } 7565 } 7566 } 7567 foffs[f] += fdof; 7568 } 7569 PetscFunctionReturn(PETSC_SUCCESS); 7570 } 7571 7572 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7573 { 7574 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7575 7576 PetscFunctionBegin; 7577 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7578 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7579 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7580 for (PetscInt p = 0; p < nPoints; p++) { 7581 PetscInt b = pnts[2 * p]; 7582 PetscInt bSecDof = 0, bOff; 7583 PetscInt cSecDof = 0; 7584 PetscSection indices_section; 7585 7586 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7587 if (!bSecDof) continue; 7588 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7589 indices_section = cSecDof > 0 ? cSec : section; 7590 if (numFields) { 7591 PetscInt fStart[32], fEnd[32]; 7592 7593 fStart[0] = 0; 7594 fEnd[0] = 0; 7595 for (PetscInt f = 0; f < numFields; f++) { 7596 PetscInt fDof = 0; 7597 7598 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7599 fStart[f + 1] = fStart[f] + fDof; 7600 fEnd[f + 1] = fStart[f + 1]; 7601 } 7602 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7603 // only apply permutations on one side 7604 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7605 for (PetscInt f = 0; f < numFields; f++) { 7606 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7607 } 7608 } else { 7609 PetscInt bEnd = 0; 7610 7611 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7612 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7613 7614 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7615 } 7616 } 7617 PetscFunctionReturn(PETSC_SUCCESS); 7618 } 7619 7620 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[]) 7621 { 7622 Mat cMat; 7623 PetscSection aSec, cSec; 7624 IS aIS; 7625 PetscInt aStart = -1, aEnd = -1; 7626 PetscInt sStart = -1, sEnd = -1; 7627 PetscInt cStart = -1, cEnd = -1; 7628 const PetscInt *anchors; 7629 PetscInt numFields, p; 7630 PetscInt newNumPoints = 0, newNumIndices = 0; 7631 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7632 PetscInt oldOffsets[32]; 7633 PetscInt newOffsets[32]; 7634 PetscInt oldOffsetsCopy[32]; 7635 PetscInt newOffsetsCopy[32]; 7636 PetscScalar *modMat = NULL; 7637 PetscBool anyConstrained = PETSC_FALSE; 7638 7639 PetscFunctionBegin; 7640 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7641 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7642 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7643 7644 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7645 /* if there are point-to-point constraints */ 7646 if (aSec) { 7647 PetscCall(PetscArrayzero(newOffsets, 32)); 7648 PetscCall(PetscArrayzero(oldOffsets, 32)); 7649 PetscCall(ISGetIndices(aIS, &anchors)); 7650 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7651 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7652 /* figure out how many points are going to be in the new element matrix 7653 * (we allow double counting, because it's all just going to be summed 7654 * into the global matrix anyway) */ 7655 for (p = 0; p < 2 * numPoints; p += 2) { 7656 PetscInt b = points[p]; 7657 PetscInt bDof = 0, bSecDof = 0; 7658 7659 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7660 if (!bSecDof) continue; 7661 7662 for (PetscInt f = 0; f < numFields; f++) { 7663 PetscInt fDof = 0; 7664 7665 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7666 oldOffsets[f + 1] += fDof; 7667 } 7668 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7669 if (bDof) { 7670 /* this point is constrained */ 7671 /* it is going to be replaced by its anchors */ 7672 PetscInt bOff, q; 7673 7674 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7675 for (q = 0; q < bDof; q++) { 7676 PetscInt a = anchors[bOff + q]; 7677 PetscInt aDof = 0; 7678 7679 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7680 if (aDof) { 7681 anyConstrained = PETSC_TRUE; 7682 newNumPoints += 1; 7683 } 7684 newNumIndices += aDof; 7685 for (PetscInt f = 0; f < numFields; ++f) { 7686 PetscInt fDof = 0; 7687 7688 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7689 newOffsets[f + 1] += fDof; 7690 } 7691 } 7692 } else { 7693 /* this point is not constrained */ 7694 newNumPoints++; 7695 newNumIndices += bSecDof; 7696 for (PetscInt f = 0; f < numFields; ++f) { 7697 PetscInt fDof; 7698 7699 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7700 newOffsets[f + 1] += fDof; 7701 } 7702 } 7703 } 7704 } 7705 if (!anyConstrained) { 7706 if (outNumPoints) *outNumPoints = 0; 7707 if (outNumIndices) *outNumIndices = 0; 7708 if (outPoints) *outPoints = NULL; 7709 if (outMat) *outMat = NULL; 7710 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7711 PetscFunctionReturn(PETSC_SUCCESS); 7712 } 7713 7714 if (outNumPoints) *outNumPoints = newNumPoints; 7715 if (outNumIndices) *outNumIndices = newNumIndices; 7716 7717 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7718 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7719 7720 if (!outPoints && !outMat) { 7721 if (offsets) { 7722 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7723 } 7724 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7725 PetscFunctionReturn(PETSC_SUCCESS); 7726 } 7727 7728 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7729 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7730 7731 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7732 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7733 7734 /* output arrays */ 7735 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7736 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7737 7738 // get the new Points 7739 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7740 PetscInt b = points[2 * p]; 7741 PetscInt bDof = 0, bSecDof = 0, bOff; 7742 7743 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7744 if (!bSecDof) continue; 7745 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7746 if (bDof) { 7747 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7748 for (PetscInt q = 0; q < bDof; q++) { 7749 PetscInt a = anchors[bOff + q], aDof = 0; 7750 7751 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7752 if (aDof) { 7753 newPoints[2 * newP] = a; 7754 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7755 newP++; 7756 } 7757 } 7758 } else { 7759 newPoints[2 * newP] = b; 7760 newPoints[2 * newP + 1] = points[2 * p + 1]; 7761 newP++; 7762 } 7763 } 7764 7765 if (outMat) { 7766 PetscScalar *tmpMat; 7767 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7768 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7769 7770 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7771 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7772 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7773 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7774 7775 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7776 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7777 7778 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7779 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7780 7781 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7782 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7783 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7784 // for each field, insert the anchor modification into modMat 7785 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7786 PetscInt fStart = oldOffsets[f]; 7787 PetscInt fNewStart = newOffsets[f]; 7788 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7789 PetscInt b = points[2 * p]; 7790 PetscInt bDof = 0, bSecDof = 0, bOff; 7791 7792 if (b >= sStart && b < sEnd) { 7793 if (numFields) { 7794 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7795 } else { 7796 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7797 } 7798 } 7799 if (!bSecDof) continue; 7800 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7801 if (bDof) { 7802 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7803 for (PetscInt q = 0; q < bDof; q++, newP++) { 7804 PetscInt a = anchors[bOff + q], aDof = 0; 7805 7806 if (a >= sStart && a < sEnd) { 7807 if (numFields) { 7808 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7809 } else { 7810 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7811 } 7812 } 7813 if (aDof) { 7814 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7815 for (PetscInt d = 0; d < bSecDof; d++) { 7816 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7817 } 7818 } 7819 oNew += aDof; 7820 } 7821 } else { 7822 // Insert the identity matrix in this block 7823 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7824 oNew += bSecDof; 7825 newP++; 7826 } 7827 o += bSecDof; 7828 } 7829 } 7830 7831 *outMat = modMat; 7832 7833 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7834 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7835 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7836 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7837 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7838 } 7839 PetscCall(ISRestoreIndices(aIS, &anchors)); 7840 7841 /* output */ 7842 if (outPoints) { 7843 *outPoints = newPoints; 7844 } else { 7845 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7846 } 7847 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7848 PetscFunctionReturn(PETSC_SUCCESS); 7849 } 7850 7851 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) 7852 { 7853 PetscScalar *modMat = NULL; 7854 PetscInt newNumIndices = -1; 7855 7856 PetscFunctionBegin; 7857 /* 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. 7858 modMat is that matrix C */ 7859 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7860 if (outNumIndices) *outNumIndices = newNumIndices; 7861 if (modMat) { 7862 const PetscScalar *newValues = values; 7863 7864 if (multiplyRight) { 7865 PetscScalar *newNewValues = NULL; 7866 PetscBLASInt M = newNumIndices; 7867 PetscBLASInt N = numRows; 7868 PetscBLASInt K = numIndices; 7869 PetscScalar a = 1.0, b = 0.0; 7870 7871 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); 7872 7873 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7874 // row-major to column-major conversion, right multiplication becomes left multiplication 7875 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7876 7877 numCols = newNumIndices; 7878 newValues = newNewValues; 7879 } 7880 7881 if (multiplyLeft) { 7882 PetscScalar *newNewValues = NULL; 7883 PetscBLASInt M = numCols; 7884 PetscBLASInt N = newNumIndices; 7885 PetscBLASInt K = numIndices; 7886 PetscScalar a = 1.0, b = 0.0; 7887 7888 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); 7889 7890 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7891 // row-major to column-major conversion, left multiplication becomes right multiplication 7892 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7893 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7894 newValues = newNewValues; 7895 } 7896 *outValues = (PetscScalar *)newValues; 7897 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7898 } 7899 PetscFunctionReturn(PETSC_SUCCESS); 7900 } 7901 7902 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) 7903 { 7904 PetscFunctionBegin; 7905 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7906 PetscFunctionReturn(PETSC_SUCCESS); 7907 } 7908 7909 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7910 { 7911 /* Closure ordering */ 7912 PetscSection clSection; 7913 IS clPoints; 7914 const PetscInt *clp; 7915 PetscInt *points; 7916 PetscInt Ncl, Ni = 0; 7917 7918 PetscFunctionBeginHot; 7919 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7920 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7921 PetscInt dof; 7922 7923 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7924 Ni += dof; 7925 } 7926 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7927 *closureSize = Ni; 7928 PetscFunctionReturn(PETSC_SUCCESS); 7929 } 7930 7931 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) 7932 { 7933 /* Closure ordering */ 7934 PetscSection clSection; 7935 IS clPoints; 7936 const PetscInt *clp; 7937 PetscInt *points; 7938 const PetscInt *clperm = NULL; 7939 /* Dof permutation and sign flips */ 7940 const PetscInt **perms[32] = {NULL}; 7941 const PetscScalar **flips[32] = {NULL}; 7942 PetscScalar *valCopy = NULL; 7943 /* Hanging node constraints */ 7944 PetscInt *pointsC = NULL; 7945 PetscScalar *valuesC = NULL; 7946 PetscInt NclC, NiC; 7947 7948 PetscInt *idx; 7949 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7950 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7951 PetscInt idxStart, idxEnd; 7952 PetscInt nRows, nCols; 7953 7954 PetscFunctionBeginHot; 7955 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7956 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7957 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7958 PetscAssertPointer(numRows, 6); 7959 PetscAssertPointer(numCols, 7); 7960 if (indices) PetscAssertPointer(indices, 8); 7961 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7962 if (values) PetscAssertPointer(values, 10); 7963 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7964 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7965 PetscCall(PetscArrayzero(offsets, 32)); 7966 /* 1) Get points in closure */ 7967 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7968 if (useClPerm) { 7969 PetscInt depth, clsize; 7970 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7971 for (clsize = 0, p = 0; p < Ncl; p++) { 7972 PetscInt dof; 7973 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7974 clsize += dof; 7975 } 7976 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7977 } 7978 /* 2) Get number of indices on these points and field offsets from section */ 7979 for (p = 0; p < Ncl * 2; p += 2) { 7980 PetscInt dof, fdof; 7981 7982 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7983 for (f = 0; f < Nf; ++f) { 7984 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7985 offsets[f + 1] += fdof; 7986 } 7987 Ni += dof; 7988 } 7989 if (*numRows == -1) *numRows = Ni; 7990 if (*numCols == -1) *numCols = Ni; 7991 nRows = *numRows; 7992 nCols = *numCols; 7993 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7994 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7995 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7996 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7997 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7998 for (f = 0; f < PetscMax(1, Nf); ++f) { 7999 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8000 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8001 /* may need to apply sign changes to the element matrix */ 8002 if (values && flips[f]) { 8003 PetscInt foffset = offsets[f]; 8004 8005 for (p = 0; p < Ncl; ++p) { 8006 PetscInt pnt = points[2 * p], fdof; 8007 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8008 8009 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8010 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8011 if (flip) { 8012 PetscInt i, j, k; 8013 8014 if (!valCopy) { 8015 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8016 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8017 *values = valCopy; 8018 } 8019 for (i = 0; i < fdof; ++i) { 8020 PetscScalar fval = flip[i]; 8021 8022 if (multiplyRight) { 8023 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8024 } 8025 if (multiplyLeft) { 8026 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8027 } 8028 } 8029 } 8030 foffset += fdof; 8031 } 8032 } 8033 } 8034 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8035 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8036 if (NclC) { 8037 if (multiplyRight) { *numCols = nCols = NiC; } 8038 if (multiplyLeft) { *numRows = nRows = NiC; } 8039 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8040 for (f = 0; f < PetscMax(1, Nf); ++f) { 8041 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8042 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8043 } 8044 for (f = 0; f < PetscMax(1, Nf); ++f) { 8045 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8046 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8047 } 8048 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8049 Ncl = NclC; 8050 Ni = NiC; 8051 points = pointsC; 8052 if (values) *values = valuesC; 8053 } 8054 /* 5) Calculate indices */ 8055 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8056 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8057 if (Nf) { 8058 PetscInt idxOff; 8059 PetscBool useFieldOffsets; 8060 8061 if (outOffsets) { 8062 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8063 } 8064 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8065 if (useFieldOffsets) { 8066 for (p = 0; p < Ncl; ++p) { 8067 const PetscInt pnt = points[p * 2]; 8068 8069 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8070 } 8071 } else { 8072 for (p = 0; p < Ncl; ++p) { 8073 const PetscInt pnt = points[p * 2]; 8074 8075 if (pnt < idxStart || pnt >= idxEnd) continue; 8076 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8077 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8078 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8079 * global section. */ 8080 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8081 } 8082 } 8083 } else { 8084 PetscInt off = 0, idxOff; 8085 8086 for (p = 0; p < Ncl; ++p) { 8087 const PetscInt pnt = points[p * 2]; 8088 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8089 8090 if (pnt < idxStart || pnt >= idxEnd) continue; 8091 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8092 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8093 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8094 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8095 } 8096 } 8097 /* 6) Cleanup */ 8098 for (f = 0; f < PetscMax(1, Nf); ++f) { 8099 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8100 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8101 } 8102 if (NclC) { 8103 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8104 } else { 8105 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8106 } 8107 8108 if (indices) *indices = idx; 8109 PetscFunctionReturn(PETSC_SUCCESS); 8110 } 8111 8112 /*@C 8113 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8114 8115 Not collective 8116 8117 Input Parameters: 8118 + dm - The `DM` 8119 . section - The `PetscSection` describing the points (a local section) 8120 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8121 . point - The point defining the closure 8122 - useClPerm - Use the closure point permutation if available 8123 8124 Output Parameters: 8125 + numIndices - The number of dof indices in the closure of point with the input sections 8126 . indices - The dof indices 8127 . outOffsets - Array to write the field offsets into, or `NULL` 8128 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8129 8130 Level: advanced 8131 8132 Notes: 8133 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8134 8135 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8136 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8137 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8138 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8139 indices (with the above semantics) are implied. 8140 8141 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8142 `PetscSection`, `DMGetGlobalSection()` 8143 @*/ 8144 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8145 { 8146 PetscInt numRows = -1, numCols = -1; 8147 8148 PetscFunctionBeginHot; 8149 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8150 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8151 *numIndices = numRows; 8152 PetscFunctionReturn(PETSC_SUCCESS); 8153 } 8154 8155 /*@C 8156 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8157 8158 Not collective 8159 8160 Input Parameters: 8161 + dm - The `DM` 8162 . section - The `PetscSection` describing the points (a local section) 8163 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8164 . point - The point defining the closure 8165 - useClPerm - Use the closure point permutation if available 8166 8167 Output Parameters: 8168 + numIndices - The number of dof indices in the closure of point with the input sections 8169 . indices - The dof indices 8170 . outOffsets - Array to write the field offsets into, or `NULL` 8171 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8172 8173 Level: advanced 8174 8175 Notes: 8176 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8177 8178 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8179 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8180 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8181 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8182 indices (with the above semantics) are implied. 8183 8184 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8185 @*/ 8186 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8187 { 8188 PetscFunctionBegin; 8189 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8190 PetscAssertPointer(indices, 7); 8191 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8192 PetscFunctionReturn(PETSC_SUCCESS); 8193 } 8194 8195 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8196 { 8197 DM_Plex *mesh = (DM_Plex *)dm->data; 8198 PetscInt *indices; 8199 PetscInt numIndices; 8200 const PetscScalar *valuesOrig = values; 8201 PetscErrorCode ierr; 8202 8203 PetscFunctionBegin; 8204 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8205 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8206 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8207 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8208 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8209 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8210 8211 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8212 8213 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8214 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8215 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8216 if (ierr) { 8217 PetscMPIInt rank; 8218 8219 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8220 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8221 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8222 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8223 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8224 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8225 } 8226 if (mesh->printFEM > 1) { 8227 PetscInt i; 8228 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8229 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8230 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8231 } 8232 8233 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8234 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8235 PetscFunctionReturn(PETSC_SUCCESS); 8236 } 8237 8238 /*@C 8239 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8240 8241 Not collective 8242 8243 Input Parameters: 8244 + dm - The `DM` 8245 . section - The section describing the layout in `v`, or `NULL` to use the default section 8246 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8247 . A - The matrix 8248 . point - The point in the `DM` 8249 . values - The array of values 8250 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8251 8252 Level: intermediate 8253 8254 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8255 @*/ 8256 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8257 { 8258 PetscFunctionBegin; 8259 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8260 PetscFunctionReturn(PETSC_SUCCESS); 8261 } 8262 8263 /*@C 8264 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8265 8266 Not collective 8267 8268 Input Parameters: 8269 + dmRow - The `DM` for the row fields 8270 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8271 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8272 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8273 . dmCol - The `DM` for the column fields 8274 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8275 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8276 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8277 . A - The matrix 8278 . point - The point in the `DM` 8279 . values - The array of values 8280 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8281 8282 Level: intermediate 8283 8284 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8285 @*/ 8286 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) 8287 { 8288 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8289 PetscInt *indicesRow, *indicesCol; 8290 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8291 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8292 8293 PetscErrorCode ierr; 8294 8295 PetscFunctionBegin; 8296 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8297 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8298 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8299 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8300 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8301 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8302 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8303 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8304 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8305 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8306 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8307 8308 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8309 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8310 valuesV1 = valuesV0; 8311 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8312 valuesV2 = valuesV1; 8313 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8314 8315 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8316 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8317 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8318 if (ierr) { 8319 PetscMPIInt rank; 8320 8321 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8322 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8323 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8324 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8325 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8326 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8327 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8328 } 8329 8330 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8331 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8332 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8333 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8334 PetscFunctionReturn(PETSC_SUCCESS); 8335 } 8336 8337 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8338 { 8339 DM_Plex *mesh = (DM_Plex *)dmf->data; 8340 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8341 PetscInt *cpoints = NULL; 8342 PetscInt *findices, *cindices; 8343 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8344 PetscInt foffsets[32], coffsets[32]; 8345 DMPolytopeType ct; 8346 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8347 PetscErrorCode ierr; 8348 8349 PetscFunctionBegin; 8350 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8351 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8352 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8353 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8354 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8355 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8356 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8357 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8358 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8359 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8360 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8361 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8362 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8363 PetscCall(PetscArrayzero(foffsets, 32)); 8364 PetscCall(PetscArrayzero(coffsets, 32)); 8365 /* Column indices */ 8366 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8367 maxFPoints = numCPoints; 8368 /* Compress out points not in the section */ 8369 /* TODO: Squeeze out points with 0 dof as well */ 8370 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8371 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8372 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8373 cpoints[q * 2] = cpoints[p]; 8374 cpoints[q * 2 + 1] = cpoints[p + 1]; 8375 ++q; 8376 } 8377 } 8378 numCPoints = q; 8379 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8380 PetscInt fdof; 8381 8382 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8383 if (!dof) continue; 8384 for (f = 0; f < numFields; ++f) { 8385 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8386 coffsets[f + 1] += fdof; 8387 } 8388 numCIndices += dof; 8389 } 8390 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8391 /* Row indices */ 8392 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8393 { 8394 DMPlexTransform tr; 8395 DMPolytopeType *rct; 8396 PetscInt *rsize, *rcone, *rornt, Nt; 8397 8398 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8399 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8400 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8401 numSubcells = rsize[Nt - 1]; 8402 PetscCall(DMPlexTransformDestroy(&tr)); 8403 } 8404 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8405 for (r = 0, q = 0; r < numSubcells; ++r) { 8406 /* TODO Map from coarse to fine cells */ 8407 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8408 /* Compress out points not in the section */ 8409 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8410 for (p = 0; p < numFPoints * 2; p += 2) { 8411 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8412 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8413 if (!dof) continue; 8414 for (s = 0; s < q; ++s) 8415 if (fpoints[p] == ftotpoints[s * 2]) break; 8416 if (s < q) continue; 8417 ftotpoints[q * 2] = fpoints[p]; 8418 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8419 ++q; 8420 } 8421 } 8422 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8423 } 8424 numFPoints = q; 8425 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8426 PetscInt fdof; 8427 8428 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8429 if (!dof) continue; 8430 for (f = 0; f < numFields; ++f) { 8431 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8432 foffsets[f + 1] += fdof; 8433 } 8434 numFIndices += dof; 8435 } 8436 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8437 8438 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8439 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8440 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8441 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8442 if (numFields) { 8443 const PetscInt **permsF[32] = {NULL}; 8444 const PetscInt **permsC[32] = {NULL}; 8445 8446 for (f = 0; f < numFields; f++) { 8447 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8448 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8449 } 8450 for (p = 0; p < numFPoints; p++) { 8451 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8452 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8453 } 8454 for (p = 0; p < numCPoints; p++) { 8455 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8456 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8457 } 8458 for (f = 0; f < numFields; f++) { 8459 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8460 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8461 } 8462 } else { 8463 const PetscInt **permsF = NULL; 8464 const PetscInt **permsC = NULL; 8465 8466 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8467 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8468 for (p = 0, off = 0; p < numFPoints; p++) { 8469 const PetscInt *perm = permsF ? permsF[p] : NULL; 8470 8471 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8472 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8473 } 8474 for (p = 0, off = 0; p < numCPoints; p++) { 8475 const PetscInt *perm = permsC ? permsC[p] : NULL; 8476 8477 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8478 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8479 } 8480 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8481 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8482 } 8483 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8484 /* TODO: flips */ 8485 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8486 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8487 if (ierr) { 8488 PetscMPIInt rank; 8489 8490 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8491 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8492 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8493 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8494 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8495 } 8496 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8497 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8498 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8499 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8500 PetscFunctionReturn(PETSC_SUCCESS); 8501 } 8502 8503 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8504 { 8505 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8506 PetscInt *cpoints = NULL; 8507 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8508 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8509 DMPolytopeType ct; 8510 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8511 8512 PetscFunctionBegin; 8513 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8514 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8515 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8516 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8517 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8518 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8519 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8520 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8521 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8522 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8523 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8524 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8525 /* Column indices */ 8526 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8527 maxFPoints = numCPoints; 8528 /* Compress out points not in the section */ 8529 /* TODO: Squeeze out points with 0 dof as well */ 8530 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8531 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8532 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8533 cpoints[q * 2] = cpoints[p]; 8534 cpoints[q * 2 + 1] = cpoints[p + 1]; 8535 ++q; 8536 } 8537 } 8538 numCPoints = q; 8539 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8540 PetscInt fdof; 8541 8542 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8543 if (!dof) continue; 8544 for (f = 0; f < numFields; ++f) { 8545 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8546 coffsets[f + 1] += fdof; 8547 } 8548 numCIndices += dof; 8549 } 8550 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8551 /* Row indices */ 8552 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8553 { 8554 DMPlexTransform tr; 8555 DMPolytopeType *rct; 8556 PetscInt *rsize, *rcone, *rornt, Nt; 8557 8558 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8559 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8560 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8561 numSubcells = rsize[Nt - 1]; 8562 PetscCall(DMPlexTransformDestroy(&tr)); 8563 } 8564 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8565 for (r = 0, q = 0; r < numSubcells; ++r) { 8566 /* TODO Map from coarse to fine cells */ 8567 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8568 /* Compress out points not in the section */ 8569 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8570 for (p = 0; p < numFPoints * 2; p += 2) { 8571 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8572 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8573 if (!dof) continue; 8574 for (s = 0; s < q; ++s) 8575 if (fpoints[p] == ftotpoints[s * 2]) break; 8576 if (s < q) continue; 8577 ftotpoints[q * 2] = fpoints[p]; 8578 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8579 ++q; 8580 } 8581 } 8582 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8583 } 8584 numFPoints = q; 8585 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8586 PetscInt fdof; 8587 8588 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8589 if (!dof) continue; 8590 for (f = 0; f < numFields; ++f) { 8591 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8592 foffsets[f + 1] += fdof; 8593 } 8594 numFIndices += dof; 8595 } 8596 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8597 8598 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8599 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8600 if (numFields) { 8601 const PetscInt **permsF[32] = {NULL}; 8602 const PetscInt **permsC[32] = {NULL}; 8603 8604 for (f = 0; f < numFields; f++) { 8605 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8606 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8607 } 8608 for (p = 0; p < numFPoints; p++) { 8609 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8610 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8611 } 8612 for (p = 0; p < numCPoints; p++) { 8613 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8614 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8615 } 8616 for (f = 0; f < numFields; f++) { 8617 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8618 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8619 } 8620 } else { 8621 const PetscInt **permsF = NULL; 8622 const PetscInt **permsC = NULL; 8623 8624 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8625 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8626 for (p = 0, off = 0; p < numFPoints; p++) { 8627 const PetscInt *perm = permsF ? permsF[p] : NULL; 8628 8629 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8630 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8631 } 8632 for (p = 0, off = 0; p < numCPoints; p++) { 8633 const PetscInt *perm = permsC ? permsC[p] : NULL; 8634 8635 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8636 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8637 } 8638 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8639 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8640 } 8641 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8642 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8643 PetscFunctionReturn(PETSC_SUCCESS); 8644 } 8645 8646 /*@ 8647 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8648 8649 Input Parameter: 8650 . dm - The `DMPLEX` object 8651 8652 Output Parameter: 8653 . cellHeight - The height of a cell 8654 8655 Level: developer 8656 8657 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8658 @*/ 8659 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8660 { 8661 DM_Plex *mesh = (DM_Plex *)dm->data; 8662 8663 PetscFunctionBegin; 8664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8665 PetscAssertPointer(cellHeight, 2); 8666 *cellHeight = mesh->vtkCellHeight; 8667 PetscFunctionReturn(PETSC_SUCCESS); 8668 } 8669 8670 /*@ 8671 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8672 8673 Input Parameters: 8674 + dm - The `DMPLEX` object 8675 - cellHeight - The height of a cell 8676 8677 Level: developer 8678 8679 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8680 @*/ 8681 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8682 { 8683 DM_Plex *mesh = (DM_Plex *)dm->data; 8684 8685 PetscFunctionBegin; 8686 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8687 mesh->vtkCellHeight = cellHeight; 8688 PetscFunctionReturn(PETSC_SUCCESS); 8689 } 8690 8691 /*@ 8692 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8693 8694 Input Parameters: 8695 + dm - The `DMPLEX` object 8696 - ct - The `DMPolytopeType` of the cell 8697 8698 Output Parameters: 8699 + start - The first cell of this type, or `NULL` 8700 - end - The upper bound on this celltype, or `NULL` 8701 8702 Level: advanced 8703 8704 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8705 @*/ 8706 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8707 { 8708 DM_Plex *mesh = (DM_Plex *)dm->data; 8709 DMLabel label; 8710 PetscInt pStart, pEnd; 8711 8712 PetscFunctionBegin; 8713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8714 if (start) { 8715 PetscAssertPointer(start, 3); 8716 *start = 0; 8717 } 8718 if (end) { 8719 PetscAssertPointer(end, 4); 8720 *end = 0; 8721 } 8722 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8723 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8724 if (mesh->tr) { 8725 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8726 } else { 8727 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8728 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8729 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8730 } 8731 PetscFunctionReturn(PETSC_SUCCESS); 8732 } 8733 8734 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8735 { 8736 PetscSection section, globalSection; 8737 PetscInt *numbers, p; 8738 8739 PetscFunctionBegin; 8740 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8741 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8742 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8743 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8744 PetscCall(PetscSectionSetUp(section)); 8745 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8746 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8747 for (p = pStart; p < pEnd; ++p) { 8748 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8749 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8750 else numbers[p - pStart] += shift; 8751 } 8752 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8753 if (globalSize) { 8754 PetscLayout layout; 8755 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8756 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8757 PetscCall(PetscLayoutDestroy(&layout)); 8758 } 8759 PetscCall(PetscSectionDestroy(§ion)); 8760 PetscCall(PetscSectionDestroy(&globalSection)); 8761 PetscFunctionReturn(PETSC_SUCCESS); 8762 } 8763 8764 /*@ 8765 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8766 8767 Input Parameters: 8768 + dm - The `DMPLEX` object 8769 - includeAll - Whether to include all cells, or just the simplex and box cells 8770 8771 Output Parameter: 8772 . globalCellNumbers - Global cell numbers for all cells on this process 8773 8774 Level: developer 8775 8776 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8777 @*/ 8778 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8779 { 8780 PetscInt cellHeight, cStart, cEnd; 8781 8782 PetscFunctionBegin; 8783 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8784 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8785 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8786 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8787 PetscFunctionReturn(PETSC_SUCCESS); 8788 } 8789 8790 /*@ 8791 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8792 8793 Input Parameter: 8794 . dm - The `DMPLEX` object 8795 8796 Output Parameter: 8797 . globalCellNumbers - Global cell numbers for all cells on this process 8798 8799 Level: developer 8800 8801 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8802 @*/ 8803 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8804 { 8805 DM_Plex *mesh = (DM_Plex *)dm->data; 8806 8807 PetscFunctionBegin; 8808 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8809 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8810 *globalCellNumbers = mesh->globalCellNumbers; 8811 PetscFunctionReturn(PETSC_SUCCESS); 8812 } 8813 8814 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8815 { 8816 PetscInt vStart, vEnd; 8817 8818 PetscFunctionBegin; 8819 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8820 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8821 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8822 PetscFunctionReturn(PETSC_SUCCESS); 8823 } 8824 8825 /*@ 8826 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8827 8828 Input Parameter: 8829 . dm - The `DMPLEX` object 8830 8831 Output Parameter: 8832 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8833 8834 Level: developer 8835 8836 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8837 @*/ 8838 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8839 { 8840 DM_Plex *mesh = (DM_Plex *)dm->data; 8841 8842 PetscFunctionBegin; 8843 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8844 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8845 *globalVertexNumbers = mesh->globalVertexNumbers; 8846 PetscFunctionReturn(PETSC_SUCCESS); 8847 } 8848 8849 /*@ 8850 DMPlexCreatePointNumbering - Create a global numbering for all points. 8851 8852 Collective 8853 8854 Input Parameter: 8855 . dm - The `DMPLEX` object 8856 8857 Output Parameter: 8858 . globalPointNumbers - Global numbers for all points on this process 8859 8860 Level: developer 8861 8862 Notes: 8863 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8864 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8865 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8866 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8867 8868 The partitioned mesh is 8869 ``` 8870 (2)--0--(3)--1--(4) (1)--0--(2) 8871 ``` 8872 and its global numbering is 8873 ``` 8874 (3)--0--(4)--1--(5)--2--(6) 8875 ``` 8876 Then the global numbering is provided as 8877 ``` 8878 [0] Number of indices in set 5 8879 [0] 0 0 8880 [0] 1 1 8881 [0] 2 3 8882 [0] 3 4 8883 [0] 4 -6 8884 [1] Number of indices in set 3 8885 [1] 0 2 8886 [1] 1 5 8887 [1] 2 6 8888 ``` 8889 8890 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8891 @*/ 8892 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8893 { 8894 IS nums[4]; 8895 PetscInt depths[4], gdepths[4], starts[4]; 8896 PetscInt depth, d, shift = 0; 8897 PetscBool empty = PETSC_FALSE; 8898 8899 PetscFunctionBegin; 8900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8901 PetscCall(DMPlexGetDepth(dm, &depth)); 8902 // For unstratified meshes use dim instead of depth 8903 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8904 // If any stratum is empty, we must mark all empty 8905 for (d = 0; d <= depth; ++d) { 8906 PetscInt end; 8907 8908 depths[d] = depth - d; 8909 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8910 if (!(starts[d] - end)) empty = PETSC_TRUE; 8911 } 8912 if (empty) 8913 for (d = 0; d <= depth; ++d) { 8914 depths[d] = -1; 8915 starts[d] = -1; 8916 } 8917 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8918 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8919 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]); 8920 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8921 for (d = 0; d <= depth; ++d) { 8922 PetscInt pStart, pEnd, gsize; 8923 8924 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8925 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8926 shift += gsize; 8927 } 8928 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8929 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8930 PetscFunctionReturn(PETSC_SUCCESS); 8931 } 8932 8933 /*@ 8934 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8935 8936 Collective 8937 8938 Input Parameter: 8939 . dm - The `DMPLEX` object 8940 8941 Output Parameter: 8942 . globalEdgeNumbers - Global numbers for all edges on this process 8943 8944 Level: developer 8945 8946 Notes: 8947 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). In the IS, owned edges will have their non-negative value while edges owned by different ranks will be involuted -(idx+1). 8948 8949 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8950 @*/ 8951 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8952 { 8953 PetscSF sf; 8954 PetscInt eStart, eEnd; 8955 8956 PetscFunctionBegin; 8957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8958 PetscCall(DMGetPointSF(dm, &sf)); 8959 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8960 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8961 PetscFunctionReturn(PETSC_SUCCESS); 8962 } 8963 8964 /*@ 8965 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8966 8967 Input Parameter: 8968 . dm - The `DMPLEX` object 8969 8970 Output Parameter: 8971 . ranks - The rank field 8972 8973 Options Database Key: 8974 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8975 8976 Level: intermediate 8977 8978 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8979 @*/ 8980 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8981 { 8982 DM rdm; 8983 PetscFE fe; 8984 PetscScalar *r; 8985 PetscMPIInt rank; 8986 DMPolytopeType ct; 8987 PetscInt dim, cStart, cEnd, c; 8988 PetscBool simplex; 8989 8990 PetscFunctionBeginUser; 8991 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8992 PetscAssertPointer(ranks, 2); 8993 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8994 PetscCall(DMClone(dm, &rdm)); 8995 PetscCall(DMGetDimension(rdm, &dim)); 8996 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8997 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8998 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8999 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9000 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9001 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9002 PetscCall(PetscFEDestroy(&fe)); 9003 PetscCall(DMCreateDS(rdm)); 9004 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9005 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9006 PetscCall(VecGetArray(*ranks, &r)); 9007 for (c = cStart; c < cEnd; ++c) { 9008 PetscScalar *lr; 9009 9010 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9011 if (lr) *lr = rank; 9012 } 9013 PetscCall(VecRestoreArray(*ranks, &r)); 9014 PetscCall(DMDestroy(&rdm)); 9015 PetscFunctionReturn(PETSC_SUCCESS); 9016 } 9017 9018 /*@ 9019 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9020 9021 Input Parameters: 9022 + dm - The `DMPLEX` 9023 - label - The `DMLabel` 9024 9025 Output Parameter: 9026 . val - The label value field 9027 9028 Options Database Key: 9029 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9030 9031 Level: intermediate 9032 9033 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9034 @*/ 9035 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9036 { 9037 DM rdm, plex; 9038 Vec lval; 9039 PetscSection section; 9040 PetscFE fe; 9041 PetscScalar *v; 9042 PetscInt dim, pStart, pEnd, p, cStart; 9043 DMPolytopeType ct; 9044 char name[PETSC_MAX_PATH_LEN]; 9045 const char *lname, *prefix; 9046 9047 PetscFunctionBeginUser; 9048 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9049 PetscAssertPointer(label, 2); 9050 PetscAssertPointer(val, 3); 9051 PetscCall(DMClone(dm, &rdm)); 9052 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9053 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9054 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9055 PetscCall(DMDestroy(&plex)); 9056 PetscCall(DMGetDimension(rdm, &dim)); 9057 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9058 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9059 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9060 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9061 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9062 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9063 PetscCall(PetscFEDestroy(&fe)); 9064 PetscCall(DMCreateDS(rdm)); 9065 PetscCall(DMCreateGlobalVector(rdm, val)); 9066 PetscCall(DMCreateLocalVector(rdm, &lval)); 9067 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9068 PetscCall(DMGetLocalSection(rdm, §ion)); 9069 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9070 PetscCall(VecGetArray(lval, &v)); 9071 for (p = pStart; p < pEnd; ++p) { 9072 PetscInt cval, dof, off; 9073 9074 PetscCall(PetscSectionGetDof(section, p, &dof)); 9075 if (!dof) continue; 9076 PetscCall(DMLabelGetValue(label, p, &cval)); 9077 PetscCall(PetscSectionGetOffset(section, p, &off)); 9078 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9079 } 9080 PetscCall(VecRestoreArray(lval, &v)); 9081 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9082 PetscCall(VecDestroy(&lval)); 9083 PetscCall(DMDestroy(&rdm)); 9084 PetscFunctionReturn(PETSC_SUCCESS); 9085 } 9086 9087 /*@ 9088 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9089 9090 Input Parameter: 9091 . dm - The `DMPLEX` object 9092 9093 Level: developer 9094 9095 Notes: 9096 This is a useful diagnostic when creating meshes programmatically. 9097 9098 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9099 9100 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9101 @*/ 9102 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9103 { 9104 PetscSection coneSection, supportSection; 9105 const PetscInt *cone, *support; 9106 PetscInt coneSize, c, supportSize, s; 9107 PetscInt pStart, pEnd, p, pp, csize, ssize; 9108 PetscBool storagecheck = PETSC_TRUE; 9109 9110 PetscFunctionBegin; 9111 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9112 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9113 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9114 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9115 /* Check that point p is found in the support of its cone points, and vice versa */ 9116 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9117 for (p = pStart; p < pEnd; ++p) { 9118 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9119 PetscCall(DMPlexGetCone(dm, p, &cone)); 9120 for (c = 0; c < coneSize; ++c) { 9121 PetscBool dup = PETSC_FALSE; 9122 PetscInt d; 9123 for (d = c - 1; d >= 0; --d) { 9124 if (cone[c] == cone[d]) { 9125 dup = PETSC_TRUE; 9126 break; 9127 } 9128 } 9129 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9130 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9131 for (s = 0; s < supportSize; ++s) { 9132 if (support[s] == p) break; 9133 } 9134 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9135 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9136 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9137 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9138 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9139 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9140 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9141 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]); 9142 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9143 } 9144 } 9145 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9146 if (p != pp) { 9147 storagecheck = PETSC_FALSE; 9148 continue; 9149 } 9150 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9151 PetscCall(DMPlexGetSupport(dm, p, &support)); 9152 for (s = 0; s < supportSize; ++s) { 9153 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9154 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9155 for (c = 0; c < coneSize; ++c) { 9156 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9157 if (cone[c] != pp) { 9158 c = 0; 9159 break; 9160 } 9161 if (cone[c] == p) break; 9162 } 9163 if (c >= coneSize) { 9164 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9165 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9166 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9167 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9168 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9169 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9170 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9171 } 9172 } 9173 } 9174 if (storagecheck) { 9175 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9176 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9177 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9178 } 9179 PetscFunctionReturn(PETSC_SUCCESS); 9180 } 9181 9182 /* 9183 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. 9184 */ 9185 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9186 { 9187 DMPolytopeType cct; 9188 PetscInt ptpoints[4]; 9189 const PetscInt *cone, *ccone, *ptcone; 9190 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9191 9192 PetscFunctionBegin; 9193 *unsplit = 0; 9194 switch (ct) { 9195 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9196 ptpoints[npt++] = c; 9197 break; 9198 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9199 PetscCall(DMPlexGetCone(dm, c, &cone)); 9200 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9201 for (cp = 0; cp < coneSize; ++cp) { 9202 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9203 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9204 } 9205 break; 9206 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9207 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9208 PetscCall(DMPlexGetCone(dm, c, &cone)); 9209 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9210 for (cp = 0; cp < coneSize; ++cp) { 9211 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9212 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9213 for (ccp = 0; ccp < cconeSize; ++ccp) { 9214 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9215 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9216 PetscInt p; 9217 for (p = 0; p < npt; ++p) 9218 if (ptpoints[p] == ccone[ccp]) break; 9219 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9220 } 9221 } 9222 } 9223 break; 9224 default: 9225 break; 9226 } 9227 for (pt = 0; pt < npt; ++pt) { 9228 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9229 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9230 } 9231 PetscFunctionReturn(PETSC_SUCCESS); 9232 } 9233 9234 /*@ 9235 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9236 9237 Input Parameters: 9238 + dm - The `DMPLEX` object 9239 - cellHeight - Normally 0 9240 9241 Level: developer 9242 9243 Notes: 9244 This is a useful diagnostic when creating meshes programmatically. 9245 Currently applicable only to homogeneous simplex or tensor meshes. 9246 9247 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9248 9249 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9250 @*/ 9251 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9252 { 9253 DMPlexInterpolatedFlag interp; 9254 DMPolytopeType ct; 9255 PetscInt vStart, vEnd, cStart, cEnd, c; 9256 9257 PetscFunctionBegin; 9258 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9259 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9260 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9261 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9262 for (c = cStart; c < cEnd; ++c) { 9263 PetscInt *closure = NULL; 9264 PetscInt coneSize, closureSize, cl, Nv = 0; 9265 9266 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9267 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9268 if (interp == DMPLEX_INTERPOLATED_FULL) { 9269 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9270 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)); 9271 } 9272 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9273 for (cl = 0; cl < closureSize * 2; cl += 2) { 9274 const PetscInt p = closure[cl]; 9275 if ((p >= vStart) && (p < vEnd)) ++Nv; 9276 } 9277 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9278 /* Special Case: Tensor faces with identified vertices */ 9279 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9280 PetscInt unsplit; 9281 9282 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9283 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9284 } 9285 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)); 9286 } 9287 PetscFunctionReturn(PETSC_SUCCESS); 9288 } 9289 9290 /*@ 9291 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9292 9293 Collective 9294 9295 Input Parameters: 9296 + dm - The `DMPLEX` object 9297 - cellHeight - Normally 0 9298 9299 Level: developer 9300 9301 Notes: 9302 This is a useful diagnostic when creating meshes programmatically. 9303 This routine is only relevant for meshes that are fully interpolated across all ranks. 9304 It will error out if a partially interpolated mesh is given on some rank. 9305 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9306 9307 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9308 9309 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9310 @*/ 9311 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9312 { 9313 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9314 DMPlexInterpolatedFlag interpEnum; 9315 9316 PetscFunctionBegin; 9317 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9318 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9319 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9320 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9321 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9322 PetscFunctionReturn(PETSC_SUCCESS); 9323 } 9324 9325 PetscCall(DMGetDimension(dm, &dim)); 9326 PetscCall(DMPlexGetDepth(dm, &depth)); 9327 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9328 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9329 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9330 for (c = cStart; c < cEnd; ++c) { 9331 const PetscInt *cone, *ornt, *faceSizes, *faces; 9332 const DMPolytopeType *faceTypes; 9333 DMPolytopeType ct; 9334 PetscInt numFaces, coneSize, f; 9335 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9336 9337 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9338 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9339 if (unsplit) continue; 9340 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9341 PetscCall(DMPlexGetCone(dm, c, &cone)); 9342 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9343 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9344 for (cl = 0; cl < closureSize * 2; cl += 2) { 9345 const PetscInt p = closure[cl]; 9346 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9347 } 9348 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9349 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); 9350 for (f = 0; f < numFaces; ++f) { 9351 DMPolytopeType fct; 9352 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9353 9354 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9355 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9356 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9357 const PetscInt p = fclosure[cl]; 9358 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9359 } 9360 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]); 9361 for (v = 0; v < fnumCorners; ++v) { 9362 if (fclosure[v] != faces[fOff + v]) { 9363 PetscInt v1; 9364 9365 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9366 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9367 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9368 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9369 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9370 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]); 9371 } 9372 } 9373 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9374 fOff += faceSizes[f]; 9375 } 9376 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9377 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9378 } 9379 } 9380 PetscFunctionReturn(PETSC_SUCCESS); 9381 } 9382 9383 /*@ 9384 DMPlexCheckGeometry - Check the geometry of mesh cells 9385 9386 Input Parameter: 9387 . dm - The `DMPLEX` object 9388 9389 Level: developer 9390 9391 Notes: 9392 This is a useful diagnostic when creating meshes programmatically. 9393 9394 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9395 9396 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9397 @*/ 9398 PetscErrorCode DMPlexCheckGeometry(DM dm) 9399 { 9400 Vec coordinates; 9401 PetscReal detJ, J[9], refVol = 1.0; 9402 PetscReal vol; 9403 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9404 9405 PetscFunctionBegin; 9406 PetscCall(DMGetDimension(dm, &dim)); 9407 PetscCall(DMGetCoordinateDim(dm, &dE)); 9408 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9409 PetscCall(DMPlexGetDepth(dm, &depth)); 9410 for (d = 0; d < dim; ++d) refVol *= 2.0; 9411 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9412 /* Make sure local coordinates are created, because that step is collective */ 9413 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9414 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9415 for (c = cStart; c < cEnd; ++c) { 9416 DMPolytopeType ct; 9417 PetscInt unsplit; 9418 PetscBool ignoreZeroVol = PETSC_FALSE; 9419 9420 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9421 switch (ct) { 9422 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9423 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9424 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9425 ignoreZeroVol = PETSC_TRUE; 9426 break; 9427 default: 9428 break; 9429 } 9430 switch (ct) { 9431 case DM_POLYTOPE_TRI_PRISM: 9432 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9433 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9434 case DM_POLYTOPE_PYRAMID: 9435 continue; 9436 default: 9437 break; 9438 } 9439 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9440 if (unsplit) continue; 9441 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9442 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); 9443 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9444 /* This should work with periodicity since DG coordinates should be used */ 9445 if (depth > 1) { 9446 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9447 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); 9448 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9449 } 9450 } 9451 PetscFunctionReturn(PETSC_SUCCESS); 9452 } 9453 9454 /*@ 9455 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9456 9457 Collective 9458 9459 Input Parameters: 9460 + dm - The `DMPLEX` object 9461 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9462 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9463 9464 Level: developer 9465 9466 Notes: 9467 This is mainly intended for debugging/testing purposes. 9468 9469 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9470 9471 Extra roots can come from periodic cuts, where additional points appear on the boundary 9472 9473 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9474 @*/ 9475 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9476 { 9477 PetscInt l, nleaves, nroots, overlap; 9478 const PetscInt *locals; 9479 const PetscSFNode *remotes; 9480 PetscBool distributed; 9481 MPI_Comm comm; 9482 PetscMPIInt rank; 9483 9484 PetscFunctionBegin; 9485 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9486 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9487 else pointSF = dm->sf; 9488 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9489 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9490 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9491 { 9492 PetscMPIInt mpiFlag; 9493 9494 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9495 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9496 } 9497 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9498 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9499 if (!distributed) { 9500 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); 9501 PetscFunctionReturn(PETSC_SUCCESS); 9502 } 9503 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); 9504 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9505 9506 /* Check SF graph is compatible with DMPlex chart */ 9507 { 9508 PetscInt pStart, pEnd, maxLeaf; 9509 9510 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9511 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9512 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9513 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9514 } 9515 9516 /* Check Point SF has no local points referenced */ 9517 for (l = 0; l < nleaves; l++) { 9518 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); 9519 } 9520 9521 /* Check there are no cells in interface */ 9522 if (!overlap) { 9523 PetscInt cellHeight, cStart, cEnd; 9524 9525 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9526 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9527 for (l = 0; l < nleaves; ++l) { 9528 const PetscInt point = locals ? locals[l] : l; 9529 9530 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9531 } 9532 } 9533 9534 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9535 { 9536 const PetscInt *rootdegree; 9537 9538 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9539 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9540 for (l = 0; l < nleaves; ++l) { 9541 const PetscInt point = locals ? locals[l] : l; 9542 const PetscInt *cone; 9543 PetscInt coneSize, c, idx; 9544 9545 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9546 PetscCall(DMPlexGetCone(dm, point, &cone)); 9547 for (c = 0; c < coneSize; ++c) { 9548 if (!rootdegree[cone[c]]) { 9549 if (locals) { 9550 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9551 } else { 9552 idx = (cone[c] < nleaves) ? cone[c] : -1; 9553 } 9554 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9555 } 9556 } 9557 } 9558 } 9559 PetscFunctionReturn(PETSC_SUCCESS); 9560 } 9561 9562 /*@ 9563 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9564 9565 Collective 9566 9567 Input Parameter: 9568 . dm - The `DMPLEX` object 9569 9570 Level: developer 9571 9572 Notes: 9573 This is mainly intended for debugging/testing purposes. 9574 9575 Other cell types which are disconnected would be caught by the symmetry and face checks. 9576 9577 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9578 9579 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9580 @*/ 9581 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9582 { 9583 PetscInt pStart, pEnd, vStart, vEnd; 9584 9585 PetscFunctionBegin; 9586 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9587 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9588 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9589 for (PetscInt v = vStart; v < vEnd; ++v) { 9590 PetscInt suppSize; 9591 9592 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9593 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9594 } 9595 PetscFunctionReturn(PETSC_SUCCESS); 9596 } 9597 9598 /*@ 9599 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9600 9601 Input Parameter: 9602 . dm - The `DMPLEX` object 9603 9604 Level: developer 9605 9606 Notes: 9607 This is a useful diagnostic when creating meshes programmatically. 9608 9609 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9610 9611 Currently does not include `DMPlexCheckCellShape()`. 9612 9613 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9614 @*/ 9615 PetscErrorCode DMPlexCheck(DM dm) 9616 { 9617 PetscInt cellHeight; 9618 9619 PetscFunctionBegin; 9620 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9621 PetscCall(DMPlexCheckSymmetry(dm)); 9622 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9623 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9624 PetscCall(DMPlexCheckGeometry(dm)); 9625 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9626 PetscCall(DMPlexCheckInterfaceCones(dm)); 9627 PetscCall(DMPlexCheckOrphanVertices(dm)); 9628 PetscFunctionReturn(PETSC_SUCCESS); 9629 } 9630 9631 typedef struct cell_stats { 9632 PetscReal min, max, sum, squaresum; 9633 PetscInt count; 9634 } cell_stats_t; 9635 9636 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9637 { 9638 PetscInt i, N = *len; 9639 9640 for (i = 0; i < N; i++) { 9641 cell_stats_t *A = (cell_stats_t *)a; 9642 cell_stats_t *B = (cell_stats_t *)b; 9643 9644 B->min = PetscMin(A->min, B->min); 9645 B->max = PetscMax(A->max, B->max); 9646 B->sum += A->sum; 9647 B->squaresum += A->squaresum; 9648 B->count += A->count; 9649 } 9650 } 9651 9652 /*@ 9653 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9654 9655 Collective 9656 9657 Input Parameters: 9658 + dm - The `DMPLEX` object 9659 . output - If true, statistics will be displayed on `stdout` 9660 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9661 9662 Level: developer 9663 9664 Notes: 9665 This is mainly intended for debugging/testing purposes. 9666 9667 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9668 9669 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9670 @*/ 9671 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9672 { 9673 DM dmCoarse; 9674 cell_stats_t stats, globalStats; 9675 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9676 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9677 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9678 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9679 PetscMPIInt rank, size; 9680 9681 PetscFunctionBegin; 9682 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9683 stats.min = PETSC_MAX_REAL; 9684 stats.max = PETSC_MIN_REAL; 9685 stats.sum = stats.squaresum = 0.; 9686 stats.count = 0; 9687 9688 PetscCallMPI(MPI_Comm_size(comm, &size)); 9689 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9690 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9691 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9692 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9693 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9694 for (c = cStart; c < cEnd; c++) { 9695 PetscInt i; 9696 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9697 9698 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9699 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9700 for (i = 0; i < PetscSqr(cdim); ++i) { 9701 frobJ += J[i] * J[i]; 9702 frobInvJ += invJ[i] * invJ[i]; 9703 } 9704 cond2 = frobJ * frobInvJ; 9705 cond = PetscSqrtReal(cond2); 9706 9707 stats.min = PetscMin(stats.min, cond); 9708 stats.max = PetscMax(stats.max, cond); 9709 stats.sum += cond; 9710 stats.squaresum += cond2; 9711 stats.count++; 9712 if (output && cond > limit) { 9713 PetscSection coordSection; 9714 Vec coordsLocal; 9715 PetscScalar *coords = NULL; 9716 PetscInt Nv, d, clSize, cl, *closure = NULL; 9717 9718 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9719 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9720 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9721 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9722 for (i = 0; i < Nv / cdim; ++i) { 9723 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9724 for (d = 0; d < cdim; ++d) { 9725 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9726 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9727 } 9728 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9729 } 9730 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9731 for (cl = 0; cl < clSize * 2; cl += 2) { 9732 const PetscInt edge = closure[cl]; 9733 9734 if ((edge >= eStart) && (edge < eEnd)) { 9735 PetscReal len; 9736 9737 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9738 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9739 } 9740 } 9741 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9742 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9743 } 9744 } 9745 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9746 9747 if (size > 1) { 9748 PetscMPIInt blockLengths[2] = {4, 1}; 9749 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9750 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9751 MPI_Op statReduce; 9752 9753 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9754 PetscCallMPI(MPI_Type_commit(&statType)); 9755 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9756 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9757 PetscCallMPI(MPI_Op_free(&statReduce)); 9758 PetscCallMPI(MPI_Type_free(&statType)); 9759 } else { 9760 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9761 } 9762 if (rank == 0) { 9763 count = globalStats.count; 9764 min = globalStats.min; 9765 max = globalStats.max; 9766 mean = globalStats.sum / globalStats.count; 9767 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9768 } 9769 9770 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)); 9771 PetscCall(PetscFree2(J, invJ)); 9772 9773 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9774 if (dmCoarse) { 9775 PetscBool isplex; 9776 9777 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9778 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9779 } 9780 PetscFunctionReturn(PETSC_SUCCESS); 9781 } 9782 9783 /*@ 9784 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9785 orthogonal quality below given tolerance. 9786 9787 Collective 9788 9789 Input Parameters: 9790 + dm - The `DMPLEX` object 9791 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9792 - atol - [0, 1] Absolute tolerance for tagging cells. 9793 9794 Output Parameters: 9795 + OrthQual - `Vec` containing orthogonal quality per cell 9796 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9797 9798 Options Database Keys: 9799 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9800 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9801 9802 Level: intermediate 9803 9804 Notes: 9805 Orthogonal quality is given by the following formula\: 9806 9807 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9808 9809 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 9810 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9811 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9812 calculating the cosine of the angle between these vectors. 9813 9814 Orthogonal quality ranges from 1 (best) to 0 (worst). 9815 9816 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9817 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9818 9819 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9820 9821 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9822 @*/ 9823 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9824 { 9825 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9826 PetscInt *idx; 9827 PetscScalar *oqVals; 9828 const PetscScalar *cellGeomArr, *faceGeomArr; 9829 PetscReal *ci, *fi, *Ai; 9830 MPI_Comm comm; 9831 Vec cellgeom, facegeom; 9832 DM dmFace, dmCell; 9833 IS glob; 9834 ISLocalToGlobalMapping ltog; 9835 PetscViewer vwr; 9836 9837 PetscFunctionBegin; 9838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9839 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9840 PetscAssertPointer(OrthQual, 4); 9841 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9842 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9843 PetscCall(DMGetDimension(dm, &nc)); 9844 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9845 { 9846 DMPlexInterpolatedFlag interpFlag; 9847 9848 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9849 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9850 PetscMPIInt rank; 9851 9852 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9853 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9854 } 9855 } 9856 if (OrthQualLabel) { 9857 PetscAssertPointer(OrthQualLabel, 5); 9858 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9859 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9860 } else { 9861 *OrthQualLabel = NULL; 9862 } 9863 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9864 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9865 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9866 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9867 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9868 PetscCall(VecCreate(comm, OrthQual)); 9869 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9870 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9871 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9872 PetscCall(VecSetUp(*OrthQual)); 9873 PetscCall(ISDestroy(&glob)); 9874 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9875 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9876 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9877 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9878 PetscCall(VecGetDM(cellgeom, &dmCell)); 9879 PetscCall(VecGetDM(facegeom, &dmFace)); 9880 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9881 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9882 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9883 PetscInt cellarr[2], *adj = NULL; 9884 PetscScalar *cArr, *fArr; 9885 PetscReal minvalc = 1.0, minvalf = 1.0; 9886 PetscFVCellGeom *cg; 9887 9888 idx[cellIter] = cell - cStart; 9889 cellarr[0] = cell; 9890 /* Make indexing into cellGeom easier */ 9891 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9892 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9893 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9894 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9895 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9896 PetscInt i; 9897 const PetscInt neigh = adj[cellneigh]; 9898 PetscReal normci = 0, normfi = 0, normai = 0; 9899 PetscFVCellGeom *cgneigh; 9900 PetscFVFaceGeom *fg; 9901 9902 /* Don't count ourselves in the neighbor list */ 9903 if (neigh == cell) continue; 9904 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9905 cellarr[1] = neigh; 9906 { 9907 PetscInt numcovpts; 9908 const PetscInt *covpts; 9909 9910 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9911 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9912 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9913 } 9914 9915 /* Compute c_i, f_i and their norms */ 9916 for (i = 0; i < nc; i++) { 9917 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9918 fi[i] = fg->centroid[i] - cg->centroid[i]; 9919 Ai[i] = fg->normal[i]; 9920 normci += PetscPowReal(ci[i], 2); 9921 normfi += PetscPowReal(fi[i], 2); 9922 normai += PetscPowReal(Ai[i], 2); 9923 } 9924 normci = PetscSqrtReal(normci); 9925 normfi = PetscSqrtReal(normfi); 9926 normai = PetscSqrtReal(normai); 9927 9928 /* Normalize and compute for each face-cell-normal pair */ 9929 for (i = 0; i < nc; i++) { 9930 ci[i] = ci[i] / normci; 9931 fi[i] = fi[i] / normfi; 9932 Ai[i] = Ai[i] / normai; 9933 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9934 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9935 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9936 } 9937 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9938 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9939 } 9940 PetscCall(PetscFree(adj)); 9941 PetscCall(PetscFree2(cArr, fArr)); 9942 /* Defer to cell if they're equal */ 9943 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9944 if (OrthQualLabel) { 9945 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9946 } 9947 } 9948 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9949 PetscCall(VecAssemblyBegin(*OrthQual)); 9950 PetscCall(VecAssemblyEnd(*OrthQual)); 9951 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9952 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9953 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9954 if (OrthQualLabel) { 9955 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9956 } 9957 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9958 PetscCall(PetscViewerDestroy(&vwr)); 9959 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9960 PetscFunctionReturn(PETSC_SUCCESS); 9961 } 9962 9963 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9964 * interpolator construction */ 9965 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9966 { 9967 PetscSection section, newSection, gsection; 9968 PetscSF sf; 9969 PetscBool hasConstraints, ghasConstraints; 9970 9971 PetscFunctionBegin; 9972 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9973 PetscAssertPointer(odm, 2); 9974 PetscCall(DMGetLocalSection(dm, §ion)); 9975 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9976 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9977 if (!ghasConstraints) { 9978 PetscCall(PetscObjectReference((PetscObject)dm)); 9979 *odm = dm; 9980 PetscFunctionReturn(PETSC_SUCCESS); 9981 } 9982 PetscCall(DMClone(dm, odm)); 9983 PetscCall(DMCopyFields(dm, *odm)); 9984 PetscCall(DMGetLocalSection(*odm, &newSection)); 9985 PetscCall(DMGetPointSF(*odm, &sf)); 9986 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9987 PetscCall(DMSetGlobalSection(*odm, gsection)); 9988 PetscCall(PetscSectionDestroy(&gsection)); 9989 PetscFunctionReturn(PETSC_SUCCESS); 9990 } 9991 9992 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9993 { 9994 DM dmco, dmfo; 9995 Mat interpo; 9996 Vec rscale; 9997 Vec cglobalo, clocal; 9998 Vec fglobal, fglobalo, flocal; 9999 PetscBool regular; 10000 10001 PetscFunctionBegin; 10002 PetscCall(DMGetFullDM(dmc, &dmco)); 10003 PetscCall(DMGetFullDM(dmf, &dmfo)); 10004 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10005 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10006 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10007 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10008 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10009 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10010 PetscCall(VecSet(cglobalo, 0.)); 10011 PetscCall(VecSet(clocal, 0.)); 10012 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10013 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10014 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10015 PetscCall(VecSet(fglobal, 0.)); 10016 PetscCall(VecSet(fglobalo, 0.)); 10017 PetscCall(VecSet(flocal, 0.)); 10018 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10019 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10020 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10021 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10022 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10023 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10024 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10025 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10026 *shift = fglobal; 10027 PetscCall(VecDestroy(&flocal)); 10028 PetscCall(VecDestroy(&fglobalo)); 10029 PetscCall(VecDestroy(&clocal)); 10030 PetscCall(VecDestroy(&cglobalo)); 10031 PetscCall(VecDestroy(&rscale)); 10032 PetscCall(MatDestroy(&interpo)); 10033 PetscCall(DMDestroy(&dmfo)); 10034 PetscCall(DMDestroy(&dmco)); 10035 PetscFunctionReturn(PETSC_SUCCESS); 10036 } 10037 10038 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10039 { 10040 PetscObject shifto; 10041 Vec shift; 10042 10043 PetscFunctionBegin; 10044 if (!interp) { 10045 Vec rscale; 10046 10047 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10048 PetscCall(VecDestroy(&rscale)); 10049 } else { 10050 PetscCall(PetscObjectReference((PetscObject)interp)); 10051 } 10052 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10053 if (!shifto) { 10054 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10055 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10056 shifto = (PetscObject)shift; 10057 PetscCall(VecDestroy(&shift)); 10058 } 10059 shift = (Vec)shifto; 10060 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10061 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10062 PetscCall(MatDestroy(&interp)); 10063 PetscFunctionReturn(PETSC_SUCCESS); 10064 } 10065 10066 /* Pointwise interpolation 10067 Just code FEM for now 10068 u^f = I u^c 10069 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10070 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10071 I_{ij} = psi^f_i phi^c_j 10072 */ 10073 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10074 { 10075 PetscSection gsc, gsf; 10076 PetscInt m, n; 10077 void *ctx; 10078 DM cdm; 10079 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10080 10081 PetscFunctionBegin; 10082 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10083 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10084 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10085 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10086 10087 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10088 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10089 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10090 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10091 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10092 10093 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10094 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10095 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10096 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10097 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10098 if (scaling) { 10099 /* Use naive scaling */ 10100 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10101 } 10102 PetscFunctionReturn(PETSC_SUCCESS); 10103 } 10104 10105 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10106 { 10107 VecScatter ctx; 10108 10109 PetscFunctionBegin; 10110 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10111 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10112 PetscCall(VecScatterDestroy(&ctx)); 10113 PetscFunctionReturn(PETSC_SUCCESS); 10114 } 10115 10116 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[]) 10117 { 10118 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10119 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10120 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10121 } 10122 10123 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 10124 { 10125 DM dmc; 10126 PetscDS ds; 10127 Vec ones, locmass; 10128 IS cellIS; 10129 PetscFormKey key; 10130 PetscInt depth; 10131 10132 PetscFunctionBegin; 10133 PetscCall(DMClone(dm, &dmc)); 10134 PetscCall(DMCopyDisc(dm, dmc)); 10135 PetscCall(DMGetDS(dmc, &ds)); 10136 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10137 PetscCall(DMCreateGlobalVector(dmc, mass)); 10138 PetscCall(DMGetLocalVector(dmc, &ones)); 10139 PetscCall(DMGetLocalVector(dmc, &locmass)); 10140 PetscCall(DMPlexGetDepth(dmc, &depth)); 10141 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10142 PetscCall(VecSet(locmass, 0.0)); 10143 PetscCall(VecSet(ones, 1.0)); 10144 key.label = NULL; 10145 key.value = 0; 10146 key.field = 0; 10147 key.part = 0; 10148 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10149 PetscCall(ISDestroy(&cellIS)); 10150 PetscCall(VecSet(*mass, 0.0)); 10151 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 10152 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 10153 PetscCall(DMRestoreLocalVector(dmc, &ones)); 10154 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 10155 PetscCall(DMDestroy(&dmc)); 10156 PetscFunctionReturn(PETSC_SUCCESS); 10157 } 10158 10159 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10160 { 10161 PetscSection gsc, gsf; 10162 PetscInt m, n; 10163 void *ctx; 10164 DM cdm; 10165 PetscBool regular; 10166 10167 PetscFunctionBegin; 10168 if (dmFine == dmCoarse) { 10169 DM dmc; 10170 PetscDS ds; 10171 PetscWeakForm wf; 10172 Vec u; 10173 IS cellIS; 10174 PetscFormKey key; 10175 PetscInt depth; 10176 10177 PetscCall(DMClone(dmFine, &dmc)); 10178 PetscCall(DMCopyDisc(dmFine, dmc)); 10179 PetscCall(DMGetDS(dmc, &ds)); 10180 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10181 PetscCall(PetscWeakFormClear(wf)); 10182 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10183 PetscCall(DMCreateMatrix(dmc, mass)); 10184 PetscCall(DMGetLocalVector(dmc, &u)); 10185 PetscCall(DMPlexGetDepth(dmc, &depth)); 10186 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10187 PetscCall(MatZeroEntries(*mass)); 10188 key.label = NULL; 10189 key.value = 0; 10190 key.field = 0; 10191 key.part = 0; 10192 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10193 PetscCall(ISDestroy(&cellIS)); 10194 PetscCall(DMRestoreLocalVector(dmc, &u)); 10195 PetscCall(DMDestroy(&dmc)); 10196 } else { 10197 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10198 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10199 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10200 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10201 10202 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10203 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10204 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10205 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10206 10207 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10208 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10209 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10210 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10211 } 10212 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10213 PetscFunctionReturn(PETSC_SUCCESS); 10214 } 10215 10216 /*@ 10217 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10218 10219 Input Parameter: 10220 . dm - The `DMPLEX` object 10221 10222 Output Parameter: 10223 . regular - The flag 10224 10225 Level: intermediate 10226 10227 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10228 @*/ 10229 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10230 { 10231 PetscFunctionBegin; 10232 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10233 PetscAssertPointer(regular, 2); 10234 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10235 PetscFunctionReturn(PETSC_SUCCESS); 10236 } 10237 10238 /*@ 10239 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10240 10241 Input Parameters: 10242 + dm - The `DMPLEX` object 10243 - regular - The flag 10244 10245 Level: intermediate 10246 10247 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10248 @*/ 10249 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10250 { 10251 PetscFunctionBegin; 10252 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10253 ((DM_Plex *)dm->data)->regularRefinement = regular; 10254 PetscFunctionReturn(PETSC_SUCCESS); 10255 } 10256 10257 /*@ 10258 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10259 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10260 10261 Not Collective 10262 10263 Input Parameter: 10264 . dm - The `DMPLEX` object 10265 10266 Output Parameters: 10267 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10268 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10269 10270 Level: intermediate 10271 10272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10273 @*/ 10274 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10275 { 10276 DM_Plex *plex = (DM_Plex *)dm->data; 10277 10278 PetscFunctionBegin; 10279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10280 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10281 if (anchorSection) *anchorSection = plex->anchorSection; 10282 if (anchorIS) *anchorIS = plex->anchorIS; 10283 PetscFunctionReturn(PETSC_SUCCESS); 10284 } 10285 10286 /*@ 10287 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10288 10289 Collective 10290 10291 Input Parameters: 10292 + dm - The `DMPLEX` object 10293 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10294 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10295 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10296 10297 Level: intermediate 10298 10299 Notes: 10300 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10301 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10302 combination of other points' degrees of freedom. 10303 10304 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10305 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10306 10307 The reference counts of `anchorSection` and `anchorIS` are incremented. 10308 10309 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10310 @*/ 10311 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10312 { 10313 DM_Plex *plex = (DM_Plex *)dm->data; 10314 PetscMPIInt result; 10315 10316 PetscFunctionBegin; 10317 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10318 if (anchorSection) { 10319 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10320 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10321 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10322 } 10323 if (anchorIS) { 10324 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10325 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10326 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10327 } 10328 10329 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10330 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10331 plex->anchorSection = anchorSection; 10332 10333 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10334 PetscCall(ISDestroy(&plex->anchorIS)); 10335 plex->anchorIS = anchorIS; 10336 10337 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10338 PetscInt size, a, pStart, pEnd; 10339 const PetscInt *anchors; 10340 10341 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10342 PetscCall(ISGetLocalSize(anchorIS, &size)); 10343 PetscCall(ISGetIndices(anchorIS, &anchors)); 10344 for (a = 0; a < size; a++) { 10345 PetscInt p; 10346 10347 p = anchors[a]; 10348 if (p >= pStart && p < pEnd) { 10349 PetscInt dof; 10350 10351 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10352 if (dof) { 10353 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10354 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10355 } 10356 } 10357 } 10358 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10359 } 10360 /* reset the generic constraints */ 10361 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10362 PetscFunctionReturn(PETSC_SUCCESS); 10363 } 10364 10365 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10366 { 10367 PetscSection anchorSection; 10368 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10369 10370 PetscFunctionBegin; 10371 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10372 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10373 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10374 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10375 if (numFields) { 10376 PetscInt f; 10377 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10378 10379 for (f = 0; f < numFields; f++) { 10380 PetscInt numComp; 10381 10382 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10383 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10384 } 10385 } 10386 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10387 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10388 pStart = PetscMax(pStart, sStart); 10389 pEnd = PetscMin(pEnd, sEnd); 10390 pEnd = PetscMax(pStart, pEnd); 10391 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10392 for (p = pStart; p < pEnd; p++) { 10393 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10394 if (dof) { 10395 PetscCall(PetscSectionGetDof(section, p, &dof)); 10396 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10397 for (f = 0; f < numFields; f++) { 10398 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10399 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10400 } 10401 } 10402 } 10403 PetscCall(PetscSectionSetUp(*cSec)); 10404 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10405 PetscFunctionReturn(PETSC_SUCCESS); 10406 } 10407 10408 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10409 { 10410 PetscSection aSec; 10411 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10412 const PetscInt *anchors; 10413 PetscInt numFields, f; 10414 IS aIS; 10415 MatType mtype; 10416 PetscBool iscuda, iskokkos; 10417 10418 PetscFunctionBegin; 10419 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10420 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10421 PetscCall(PetscSectionGetStorageSize(section, &n)); 10422 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10423 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10424 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10425 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10426 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10427 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10428 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10429 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10430 else mtype = MATSEQAIJ; 10431 PetscCall(MatSetType(*cMat, mtype)); 10432 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10433 PetscCall(ISGetIndices(aIS, &anchors)); 10434 /* cSec will be a subset of aSec and section */ 10435 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10436 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10437 PetscCall(PetscMalloc1(m + 1, &i)); 10438 i[0] = 0; 10439 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10440 for (p = pStart; p < pEnd; p++) { 10441 PetscInt rDof, rOff, r; 10442 10443 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10444 if (!rDof) continue; 10445 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10446 if (numFields) { 10447 for (f = 0; f < numFields; f++) { 10448 annz = 0; 10449 for (r = 0; r < rDof; r++) { 10450 a = anchors[rOff + r]; 10451 if (a < sStart || a >= sEnd) continue; 10452 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10453 annz += aDof; 10454 } 10455 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10456 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10457 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10458 } 10459 } else { 10460 annz = 0; 10461 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10462 for (q = 0; q < dof; q++) { 10463 a = anchors[rOff + q]; 10464 if (a < sStart || a >= sEnd) continue; 10465 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10466 annz += aDof; 10467 } 10468 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10469 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10470 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10471 } 10472 } 10473 nnz = i[m]; 10474 PetscCall(PetscMalloc1(nnz, &j)); 10475 offset = 0; 10476 for (p = pStart; p < pEnd; p++) { 10477 if (numFields) { 10478 for (f = 0; f < numFields; f++) { 10479 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10480 for (q = 0; q < dof; q++) { 10481 PetscInt rDof, rOff, r; 10482 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10483 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10484 for (r = 0; r < rDof; r++) { 10485 PetscInt s; 10486 10487 a = anchors[rOff + r]; 10488 if (a < sStart || a >= sEnd) continue; 10489 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10490 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10491 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10492 } 10493 } 10494 } 10495 } else { 10496 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10497 for (q = 0; q < dof; q++) { 10498 PetscInt rDof, rOff, r; 10499 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10500 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10501 for (r = 0; r < rDof; r++) { 10502 PetscInt s; 10503 10504 a = anchors[rOff + r]; 10505 if (a < sStart || a >= sEnd) continue; 10506 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10507 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10508 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10509 } 10510 } 10511 } 10512 } 10513 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10514 PetscCall(PetscFree(i)); 10515 PetscCall(PetscFree(j)); 10516 PetscCall(ISRestoreIndices(aIS, &anchors)); 10517 PetscFunctionReturn(PETSC_SUCCESS); 10518 } 10519 10520 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10521 { 10522 DM_Plex *plex = (DM_Plex *)dm->data; 10523 PetscSection anchorSection, section, cSec; 10524 Mat cMat; 10525 10526 PetscFunctionBegin; 10527 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10528 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10529 if (anchorSection) { 10530 PetscInt Nf; 10531 10532 PetscCall(DMGetLocalSection(dm, §ion)); 10533 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10534 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10535 PetscCall(DMGetNumFields(dm, &Nf)); 10536 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10537 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10538 PetscCall(PetscSectionDestroy(&cSec)); 10539 PetscCall(MatDestroy(&cMat)); 10540 } 10541 PetscFunctionReturn(PETSC_SUCCESS); 10542 } 10543 10544 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10545 { 10546 IS subis; 10547 PetscSection section, subsection; 10548 10549 PetscFunctionBegin; 10550 PetscCall(DMGetLocalSection(dm, §ion)); 10551 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10552 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10553 /* Create subdomain */ 10554 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10555 /* Create submodel */ 10556 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10557 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10558 PetscCall(DMSetLocalSection(*subdm, subsection)); 10559 PetscCall(PetscSectionDestroy(&subsection)); 10560 PetscCall(DMCopyDisc(dm, *subdm)); 10561 /* Create map from submodel to global model */ 10562 if (is) { 10563 PetscSection sectionGlobal, subsectionGlobal; 10564 IS spIS; 10565 const PetscInt *spmap; 10566 PetscInt *subIndices; 10567 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10568 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10569 10570 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10571 PetscCall(ISGetIndices(spIS, &spmap)); 10572 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10573 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10574 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10575 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10576 for (p = pStart; p < pEnd; ++p) { 10577 PetscInt gdof, pSubSize = 0; 10578 10579 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10580 if (gdof > 0) { 10581 for (f = 0; f < Nf; ++f) { 10582 PetscInt fdof, fcdof; 10583 10584 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10585 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10586 pSubSize += fdof - fcdof; 10587 } 10588 subSize += pSubSize; 10589 if (pSubSize) { 10590 if (bs < 0) { 10591 bs = pSubSize; 10592 } else if (bs != pSubSize) { 10593 /* Layout does not admit a pointwise block size */ 10594 bs = 1; 10595 } 10596 } 10597 } 10598 } 10599 /* Must have same blocksize on all procs (some might have no points) */ 10600 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10601 bsLocal[1] = bs; 10602 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10603 if (bsMinMax[0] != bsMinMax[1]) { 10604 bs = 1; 10605 } else { 10606 bs = bsMinMax[0]; 10607 } 10608 PetscCall(PetscMalloc1(subSize, &subIndices)); 10609 for (p = pStart; p < pEnd; ++p) { 10610 PetscInt gdof, goff; 10611 10612 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10613 if (gdof > 0) { 10614 const PetscInt point = spmap[p]; 10615 10616 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10617 for (f = 0; f < Nf; ++f) { 10618 PetscInt fdof, fcdof, fc, f2, poff = 0; 10619 10620 /* Can get rid of this loop by storing field information in the global section */ 10621 for (f2 = 0; f2 < f; ++f2) { 10622 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10623 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10624 poff += fdof - fcdof; 10625 } 10626 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10627 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10628 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10629 } 10630 } 10631 } 10632 PetscCall(ISRestoreIndices(spIS, &spmap)); 10633 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10634 if (bs > 1) { 10635 /* We need to check that the block size does not come from non-contiguous fields */ 10636 PetscInt i, j, set = 1; 10637 for (i = 0; i < subSize; i += bs) { 10638 for (j = 0; j < bs; ++j) { 10639 if (subIndices[i + j] != subIndices[i] + j) { 10640 set = 0; 10641 break; 10642 } 10643 } 10644 } 10645 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10646 } 10647 /* Attach nullspace */ 10648 for (f = 0; f < Nf; ++f) { 10649 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10650 if ((*subdm)->nullspaceConstructors[f]) break; 10651 } 10652 if (f < Nf) { 10653 MatNullSpace nullSpace; 10654 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10655 10656 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10657 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10658 } 10659 } 10660 PetscFunctionReturn(PETSC_SUCCESS); 10661 } 10662 10663 /*@ 10664 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10665 10666 Input Parameters: 10667 + dm - The `DM` 10668 - dummy - unused argument 10669 10670 Options Database Key: 10671 . -dm_plex_monitor_throughput - Activate the monitor 10672 10673 Level: developer 10674 10675 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10676 @*/ 10677 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10678 { 10679 PetscLogHandler default_handler; 10680 10681 PetscFunctionBegin; 10682 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10683 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10684 if (default_handler) { 10685 PetscLogEvent event; 10686 PetscEventPerfInfo eventInfo; 10687 PetscReal cellRate, flopRate; 10688 PetscInt cStart, cEnd, Nf, N; 10689 const char *name; 10690 10691 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10692 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10693 PetscCall(DMGetNumFields(dm, &Nf)); 10694 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10695 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10696 N = (cEnd - cStart) * Nf * eventInfo.count; 10697 flopRate = eventInfo.flops / eventInfo.time; 10698 cellRate = N / eventInfo.time; 10699 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))); 10700 } else { 10701 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."); 10702 } 10703 PetscFunctionReturn(PETSC_SUCCESS); 10704 } 10705