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