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_INT_MAX, 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 PetscCallMPI(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 PetscCallMPI(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 DMPolytopeType ct; 430 PetscScalar *coords = NULL, *a = NULL; 431 const PetscScalar *coords_arr; 432 PetscBool isDG; 433 PetscInt numCoords; 434 int color[4] = {-1, -1, -1, -1}; 435 436 PetscCall(DMPlexGetCellType(dm, c, &ct)); 437 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 438 if (a) { 439 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 440 color[1] = color[2] = color[3] = color[0]; 441 } else { 442 PetscScalar *vals = NULL; 443 PetscInt numVals, va; 444 445 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 446 if (!numVals) { 447 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 448 continue; 449 } 450 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); 451 switch (numVals / Nc) { 452 case 1: /* P1 Clamped Segment Prism */ 453 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 454 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 455 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 456 break; 457 case 3: /* P1 Triangle */ 458 case 4: /* P1 Quadrangle */ 459 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 460 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 461 break; 462 case 6: /* P2 Triangle */ 463 case 8: /* P2 Quadrangle */ 464 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 465 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 466 break; 467 default: 468 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 469 } 470 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 471 } 472 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 473 switch (numCoords) { 474 case 6: 475 case 12: /* Localized triangle */ 476 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])); 477 break; 478 case 8: 479 case 16: /* Localized quadrilateral */ 480 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 481 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 482 } else { 483 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])); 484 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])); 485 } 486 break; 487 default: 488 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 489 } 490 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 491 } 492 PetscCall(VecRestoreArrayRead(fv, &array)); 493 PetscCall(PetscDrawFlush(draw)); 494 PetscCall(PetscDrawPause(draw)); 495 PetscCall(PetscDrawSave(draw)); 496 } 497 if (Nf > 1) { 498 PetscCall(VecRestoreSubVector(v, fis, &fv)); 499 PetscCall(ISDestroy(&fis)); 500 PetscCall(DMDestroy(&fdm)); 501 } 502 } 503 PetscFunctionReturn(PETSC_SUCCESS); 504 } 505 506 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 507 { 508 DM dm; 509 PetscDraw draw; 510 PetscInt dim; 511 PetscBool isnull; 512 513 PetscFunctionBegin; 514 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 515 PetscCall(PetscDrawIsNull(draw, &isnull)); 516 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 517 518 PetscCall(VecGetDM(v, &dm)); 519 PetscCall(DMGetCoordinateDim(dm, &dim)); 520 switch (dim) { 521 case 1: 522 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 523 break; 524 case 2: 525 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 526 break; 527 default: 528 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 529 } 530 PetscFunctionReturn(PETSC_SUCCESS); 531 } 532 533 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 534 { 535 DM dm; 536 Vec locv; 537 const char *name; 538 PetscSection section; 539 PetscInt pStart, pEnd; 540 PetscInt numFields; 541 PetscViewerVTKFieldType ft; 542 543 PetscFunctionBegin; 544 PetscCall(VecGetDM(v, &dm)); 545 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 546 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 547 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 548 PetscCall(VecCopy(v, locv)); 549 PetscCall(DMGetLocalSection(dm, §ion)); 550 PetscCall(PetscSectionGetNumFields(section, &numFields)); 551 if (!numFields) { 552 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 553 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 554 } else { 555 PetscInt f; 556 557 for (f = 0; f < numFields; f++) { 558 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 559 if (ft == PETSC_VTK_INVALID) continue; 560 PetscCall(PetscObjectReference((PetscObject)locv)); 561 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 562 } 563 PetscCall(VecDestroy(&locv)); 564 } 565 PetscFunctionReturn(PETSC_SUCCESS); 566 } 567 568 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 569 { 570 DM dm; 571 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 572 573 PetscFunctionBegin; 574 PetscCall(VecGetDM(v, &dm)); 575 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 576 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 577 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 578 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 579 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 580 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 581 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 582 PetscInt i, numFields; 583 PetscObject fe; 584 PetscBool fem = PETSC_FALSE; 585 Vec locv = v; 586 const char *name; 587 PetscInt step; 588 PetscReal time; 589 590 PetscCall(DMGetNumFields(dm, &numFields)); 591 for (i = 0; i < numFields; i++) { 592 PetscCall(DMGetField(dm, i, NULL, &fe)); 593 if (fe->classid == PETSCFE_CLASSID) { 594 fem = PETSC_TRUE; 595 break; 596 } 597 } 598 if (fem) { 599 PetscObject isZero; 600 601 PetscCall(DMGetLocalVector(dm, &locv)); 602 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 603 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 604 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 605 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 606 PetscCall(VecCopy(v, locv)); 607 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 608 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 609 } 610 if (isvtk) { 611 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 612 } else if (ishdf5) { 613 #if defined(PETSC_HAVE_HDF5) 614 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 615 #else 616 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 617 #endif 618 } else if (isdraw) { 619 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 620 } else if (isglvis) { 621 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 622 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 623 PetscCall(VecView_GLVis(locv, viewer)); 624 } else if (iscgns) { 625 #if defined(PETSC_HAVE_CGNS) 626 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 627 #else 628 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 629 #endif 630 } 631 if (fem) { 632 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 633 PetscCall(DMRestoreLocalVector(dm, &locv)); 634 } 635 } else { 636 PetscBool isseq; 637 638 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 639 if (isseq) PetscCall(VecView_Seq(v, viewer)); 640 else PetscCall(VecView_MPI(v, viewer)); 641 } 642 PetscFunctionReturn(PETSC_SUCCESS); 643 } 644 645 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 646 { 647 DM dm; 648 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 649 650 PetscFunctionBegin; 651 PetscCall(VecGetDM(v, &dm)); 652 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 653 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 654 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 655 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 657 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 658 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 659 if (isvtk || isdraw || isglvis || iscgns) { 660 Vec locv; 661 PetscObject isZero; 662 const char *name; 663 664 PetscCall(DMGetLocalVector(dm, &locv)); 665 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 666 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 667 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 668 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 669 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 670 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 671 PetscCall(VecView_Plex_Local(locv, viewer)); 672 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 673 PetscCall(DMRestoreLocalVector(dm, &locv)); 674 /* Call flush for proper logging of VecView timings */ 675 if (isvtk) PetscCall(PetscViewerFlush(viewer)); 676 } else if (ishdf5) { 677 #if defined(PETSC_HAVE_HDF5) 678 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 679 #else 680 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 681 #endif 682 } else if (isexodusii) { 683 #if defined(PETSC_HAVE_EXODUSII) 684 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 685 #else 686 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 687 #endif 688 } else { 689 PetscBool isseq; 690 691 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 692 if (isseq) PetscCall(VecView_Seq(v, viewer)); 693 else PetscCall(VecView_MPI(v, viewer)); 694 } 695 PetscFunctionReturn(PETSC_SUCCESS); 696 } 697 698 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 699 { 700 DM dm; 701 MPI_Comm comm; 702 PetscViewerFormat format; 703 Vec v; 704 PetscBool isvtk, ishdf5; 705 706 PetscFunctionBegin; 707 PetscCall(VecGetDM(originalv, &dm)); 708 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 709 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 710 PetscCall(PetscViewerGetFormat(viewer, &format)); 711 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 712 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 713 if (format == PETSC_VIEWER_NATIVE) { 714 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 715 /* this need a better fix */ 716 if (dm->useNatural) { 717 if (dm->sfNatural) { 718 const char *vecname; 719 PetscInt n, nroots; 720 721 PetscCall(VecGetLocalSize(originalv, &n)); 722 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 723 if (n == nroots) { 724 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 725 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 726 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 727 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 728 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 729 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 730 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 731 } else v = originalv; 732 } else v = originalv; 733 734 if (ishdf5) { 735 #if defined(PETSC_HAVE_HDF5) 736 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 737 #else 738 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 739 #endif 740 } else if (isvtk) { 741 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 742 } else { 743 PetscBool isseq; 744 745 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 746 if (isseq) PetscCall(VecView_Seq(v, viewer)); 747 else PetscCall(VecView_MPI(v, viewer)); 748 } 749 if (v != originalv) PetscCall(VecDestroy(&v)); 750 PetscFunctionReturn(PETSC_SUCCESS); 751 } 752 753 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 754 { 755 DM dm; 756 PetscBool ishdf5; 757 758 PetscFunctionBegin; 759 PetscCall(VecGetDM(v, &dm)); 760 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 761 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 762 if (ishdf5) { 763 DM dmBC; 764 Vec gv; 765 const char *name; 766 767 PetscCall(DMGetOutputDM(dm, &dmBC)); 768 PetscCall(DMGetGlobalVector(dmBC, &gv)); 769 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 770 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 771 PetscCall(VecLoad_Default(gv, viewer)); 772 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 773 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 774 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 775 } else PetscCall(VecLoad_Default(v, viewer)); 776 PetscFunctionReturn(PETSC_SUCCESS); 777 } 778 779 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 780 { 781 DM dm; 782 PetscBool ishdf5, isexodusii; 783 784 PetscFunctionBegin; 785 PetscCall(VecGetDM(v, &dm)); 786 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 787 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 788 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 789 if (ishdf5) { 790 #if defined(PETSC_HAVE_HDF5) 791 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 792 #else 793 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 794 #endif 795 } else if (isexodusii) { 796 #if defined(PETSC_HAVE_EXODUSII) 797 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 798 #else 799 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 800 #endif 801 } else PetscCall(VecLoad_Default(v, viewer)); 802 PetscFunctionReturn(PETSC_SUCCESS); 803 } 804 805 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 806 { 807 DM dm; 808 PetscViewerFormat format; 809 PetscBool ishdf5; 810 811 PetscFunctionBegin; 812 PetscCall(VecGetDM(originalv, &dm)); 813 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 814 PetscCall(PetscViewerGetFormat(viewer, &format)); 815 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 816 if (format == PETSC_VIEWER_NATIVE) { 817 if (dm->useNatural) { 818 if (dm->sfNatural) { 819 if (ishdf5) { 820 #if defined(PETSC_HAVE_HDF5) 821 Vec v; 822 const char *vecname; 823 824 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 825 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 826 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 827 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 828 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 829 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 830 PetscCall(VecDestroy(&v)); 831 #else 832 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 833 #endif 834 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 835 } 836 } else PetscCall(VecLoad_Default(originalv, viewer)); 837 } 838 PetscFunctionReturn(PETSC_SUCCESS); 839 } 840 841 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 842 { 843 PetscSection coordSection; 844 Vec coordinates; 845 DMLabel depthLabel, celltypeLabel; 846 const char *name[4]; 847 const PetscScalar *a; 848 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 849 850 PetscFunctionBegin; 851 PetscCall(DMGetDimension(dm, &dim)); 852 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 853 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 854 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 855 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 856 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 857 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 858 PetscCall(VecGetArrayRead(coordinates, &a)); 859 name[0] = "vertex"; 860 name[1] = "edge"; 861 name[dim - 1] = "face"; 862 name[dim] = "cell"; 863 for (c = cStart; c < cEnd; ++c) { 864 PetscInt *closure = NULL; 865 PetscInt closureSize, cl, ct; 866 867 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 868 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 869 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 870 PetscCall(PetscViewerASCIIPushTab(viewer)); 871 for (cl = 0; cl < closureSize * 2; cl += 2) { 872 PetscInt point = closure[cl], depth, dof, off, d, p; 873 874 if ((point < pStart) || (point >= pEnd)) continue; 875 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 876 if (!dof) continue; 877 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 878 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 879 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 880 for (p = 0; p < dof / dim; ++p) { 881 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 882 for (d = 0; d < dim; ++d) { 883 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 884 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 885 } 886 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 887 } 888 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 889 } 890 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 891 PetscCall(PetscViewerASCIIPopTab(viewer)); 892 } 893 PetscCall(VecRestoreArrayRead(coordinates, &a)); 894 PetscFunctionReturn(PETSC_SUCCESS); 895 } 896 897 typedef enum { 898 CS_CARTESIAN, 899 CS_POLAR, 900 CS_CYLINDRICAL, 901 CS_SPHERICAL 902 } CoordSystem; 903 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 904 905 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 906 { 907 PetscInt i; 908 909 PetscFunctionBegin; 910 if (dim > 3) { 911 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 912 } else { 913 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 914 915 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 916 switch (cs) { 917 case CS_CARTESIAN: 918 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 919 break; 920 case CS_POLAR: 921 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 922 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 923 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 924 break; 925 case CS_CYLINDRICAL: 926 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 927 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 928 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 929 trcoords[2] = coords[2]; 930 break; 931 case CS_SPHERICAL: 932 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 933 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 934 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 935 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 936 break; 937 } 938 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 939 } 940 PetscFunctionReturn(PETSC_SUCCESS); 941 } 942 943 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 944 { 945 DM_Plex *mesh = (DM_Plex *)dm->data; 946 DM cdm, cdmCell; 947 PetscSection coordSection, coordSectionCell; 948 Vec coordinates, coordinatesCell; 949 PetscViewerFormat format; 950 951 PetscFunctionBegin; 952 PetscCall(PetscViewerGetFormat(viewer, &format)); 953 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 954 const char *name; 955 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 956 PetscInt pStart, pEnd, p, numLabels, l; 957 PetscMPIInt rank, size; 958 959 PetscCall(DMGetCoordinateDM(dm, &cdm)); 960 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 961 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 962 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 963 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 964 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 965 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 966 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 967 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 968 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 969 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 970 PetscCall(DMGetDimension(dm, &dim)); 971 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 972 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 973 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 974 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 975 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 976 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 977 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 978 for (p = pStart; p < pEnd; ++p) { 979 PetscInt dof, off, s; 980 981 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 982 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 983 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 984 } 985 PetscCall(PetscViewerFlush(viewer)); 986 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 987 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 988 for (p = pStart; p < pEnd; ++p) { 989 PetscInt dof, off, c; 990 991 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 992 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 993 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])); 994 } 995 PetscCall(PetscViewerFlush(viewer)); 996 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 997 if (coordSection && coordinates) { 998 CoordSystem cs = CS_CARTESIAN; 999 const PetscScalar *array, *arrayCell = NULL; 1000 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1001 PetscMPIInt rank; 1002 const char *name; 1003 1004 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1005 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1006 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1007 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1008 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1009 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1010 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1011 pStart = PetscMin(pvStart, pcStart); 1012 pEnd = PetscMax(pvEnd, pcEnd); 1013 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1014 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1015 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1016 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1017 1018 PetscCall(VecGetArrayRead(coordinates, &array)); 1019 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1020 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1021 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1022 for (p = pStart; p < pEnd; ++p) { 1023 PetscInt dof, off; 1024 1025 if (p >= pvStart && p < pvEnd) { 1026 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1027 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1028 if (dof) { 1029 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1030 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1031 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1032 } 1033 } 1034 if (cdmCell && p >= pcStart && p < pcEnd) { 1035 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1036 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1037 if (dof) { 1038 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1039 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1040 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1041 } 1042 } 1043 } 1044 PetscCall(PetscViewerFlush(viewer)); 1045 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1046 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1047 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1048 } 1049 PetscCall(DMGetNumLabels(dm, &numLabels)); 1050 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1051 for (l = 0; l < numLabels; ++l) { 1052 DMLabel label; 1053 PetscBool isdepth; 1054 const char *name; 1055 1056 PetscCall(DMGetLabelName(dm, l, &name)); 1057 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1058 if (isdepth) continue; 1059 PetscCall(DMGetLabel(dm, name, &label)); 1060 PetscCall(DMLabelView(label, viewer)); 1061 } 1062 if (size > 1) { 1063 PetscSF sf; 1064 1065 PetscCall(DMGetPointSF(dm, &sf)); 1066 PetscCall(PetscSFView(sf, viewer)); 1067 } 1068 if (mesh->periodic.face_sfs) 1069 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1070 PetscCall(PetscViewerFlush(viewer)); 1071 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1072 const char *name, *color; 1073 const char *defcolors[3] = {"gray", "orange", "green"}; 1074 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1075 char lname[PETSC_MAX_PATH_LEN]; 1076 PetscReal scale = 2.0; 1077 PetscReal tikzscale = 1.0; 1078 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1079 double tcoords[3]; 1080 PetscScalar *coords; 1081 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; 1082 PetscMPIInt rank, size; 1083 char **names, **colors, **lcolors; 1084 PetscBool flg, lflg; 1085 PetscBT wp = NULL; 1086 PetscInt pEnd, pStart; 1087 1088 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1089 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1090 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1091 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1092 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1093 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1094 PetscCall(DMGetDimension(dm, &dim)); 1095 PetscCall(DMPlexGetDepth(dm, &depth)); 1096 PetscCall(DMGetNumLabels(dm, &numLabels)); 1097 numLabels = PetscMax(numLabels, 10); 1098 numColors = 10; 1099 numLColors = 10; 1100 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1101 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1102 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1103 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1104 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1105 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1106 n = 4; 1107 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1108 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1109 n = 4; 1110 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1111 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1112 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1113 if (!useLabels) numLabels = 0; 1114 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1115 if (!useColors) { 1116 numColors = 3; 1117 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1118 } 1119 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1120 if (!useColors) { 1121 numLColors = 4; 1122 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1123 } 1124 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1125 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1126 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1127 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1128 if (depth < dim) plotEdges = PETSC_FALSE; 1129 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1130 1131 /* filter points with labelvalue != labeldefaultvalue */ 1132 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1133 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1134 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1135 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1136 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1137 if (lflg) { 1138 DMLabel lbl; 1139 1140 PetscCall(DMGetLabel(dm, lname, &lbl)); 1141 if (lbl) { 1142 PetscInt val, defval; 1143 1144 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1145 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1146 for (c = pStart; c < pEnd; c++) { 1147 PetscInt *closure = NULL; 1148 PetscInt closureSize; 1149 1150 PetscCall(DMLabelGetValue(lbl, c, &val)); 1151 if (val == defval) continue; 1152 1153 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1154 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1155 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1156 } 1157 } 1158 } 1159 1160 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1161 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1162 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1164 \\documentclass[tikz]{standalone}\n\n\ 1165 \\usepackage{pgflibraryshapes}\n\ 1166 \\usetikzlibrary{backgrounds}\n\ 1167 \\usetikzlibrary{arrows}\n\ 1168 \\begin{document}\n")); 1169 if (size > 1) { 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1171 for (p = 0; p < size; ++p) { 1172 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1173 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1174 } 1175 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1176 } 1177 if (drawHasse) { 1178 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1179 1180 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1181 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1182 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1183 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1184 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1185 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1186 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1187 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1188 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1189 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1190 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1191 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1192 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1193 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1194 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1195 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1196 } 1197 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1198 1199 /* Plot vertices */ 1200 PetscCall(VecGetArray(coordinates, &coords)); 1201 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1202 for (v = vStart; v < vEnd; ++v) { 1203 PetscInt off, dof, d; 1204 PetscBool isLabeled = PETSC_FALSE; 1205 1206 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1207 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1208 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1209 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1210 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1211 for (d = 0; d < dof; ++d) { 1212 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1213 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1214 } 1215 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1216 if (dim == 3) { 1217 PetscReal tmp = tcoords[1]; 1218 tcoords[1] = tcoords[2]; 1219 tcoords[2] = -tmp; 1220 } 1221 for (d = 0; d < dof; ++d) { 1222 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1223 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1224 } 1225 if (drawHasse) color = colors[0 % numColors]; 1226 else color = colors[rank % numColors]; 1227 for (l = 0; l < numLabels; ++l) { 1228 PetscInt val; 1229 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1230 if (val >= 0) { 1231 color = lcolors[l % numLColors]; 1232 isLabeled = PETSC_TRUE; 1233 break; 1234 } 1235 } 1236 if (drawNumbers[0]) { 1237 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1238 } else if (drawColors[0]) { 1239 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1240 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1241 } 1242 PetscCall(VecRestoreArray(coordinates, &coords)); 1243 PetscCall(PetscViewerFlush(viewer)); 1244 /* Plot edges */ 1245 if (plotEdges) { 1246 PetscCall(VecGetArray(coordinates, &coords)); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1248 for (e = eStart; e < eEnd; ++e) { 1249 const PetscInt *cone; 1250 PetscInt coneSize, offA, offB, dof, d; 1251 1252 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1253 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1254 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1255 PetscCall(DMPlexGetCone(dm, e, &cone)); 1256 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1257 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1258 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1259 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1260 for (d = 0; d < dof; ++d) { 1261 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1262 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1263 } 1264 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1265 if (dim == 3) { 1266 PetscReal tmp = tcoords[1]; 1267 tcoords[1] = tcoords[2]; 1268 tcoords[2] = -tmp; 1269 } 1270 for (d = 0; d < dof; ++d) { 1271 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1272 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1273 } 1274 if (drawHasse) color = colors[1 % numColors]; 1275 else color = colors[rank % numColors]; 1276 for (l = 0; l < numLabels; ++l) { 1277 PetscInt val; 1278 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1279 if (val >= 0) { 1280 color = lcolors[l % numLColors]; 1281 break; 1282 } 1283 } 1284 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1285 } 1286 PetscCall(VecRestoreArray(coordinates, &coords)); 1287 PetscCall(PetscViewerFlush(viewer)); 1288 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1289 } 1290 /* Plot cells */ 1291 if (dim == 3 || !drawNumbers[1]) { 1292 for (e = eStart; e < eEnd; ++e) { 1293 const PetscInt *cone; 1294 1295 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1296 color = colors[rank % numColors]; 1297 for (l = 0; l < numLabels; ++l) { 1298 PetscInt val; 1299 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1300 if (val >= 0) { 1301 color = lcolors[l % numLColors]; 1302 break; 1303 } 1304 } 1305 PetscCall(DMPlexGetCone(dm, e, &cone)); 1306 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1307 } 1308 } else { 1309 DMPolytopeType ct; 1310 1311 /* Drawing a 2D polygon */ 1312 for (c = cStart; c < cEnd; ++c) { 1313 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1314 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1315 if (DMPolytopeTypeIsHybrid(ct)) { 1316 const PetscInt *cone; 1317 PetscInt coneSize, e; 1318 1319 PetscCall(DMPlexGetCone(dm, c, &cone)); 1320 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1321 for (e = 0; e < coneSize; ++e) { 1322 const PetscInt *econe; 1323 1324 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1325 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)); 1326 } 1327 } else { 1328 PetscInt *closure = NULL; 1329 PetscInt closureSize, Nv = 0, v; 1330 1331 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1332 for (p = 0; p < closureSize * 2; p += 2) { 1333 const PetscInt point = closure[p]; 1334 1335 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1336 } 1337 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1338 for (v = 0; v <= Nv; ++v) { 1339 const PetscInt vertex = closure[v % Nv]; 1340 1341 if (v > 0) { 1342 if (plotEdges) { 1343 const PetscInt *edge; 1344 PetscInt endpoints[2], ne; 1345 1346 endpoints[0] = closure[v - 1]; 1347 endpoints[1] = vertex; 1348 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1349 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1350 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1351 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1352 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1353 } 1354 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1355 } 1356 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1357 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1358 } 1359 } 1360 } 1361 for (c = cStart; c < cEnd; ++c) { 1362 double ccoords[3] = {0.0, 0.0, 0.0}; 1363 PetscBool isLabeled = PETSC_FALSE; 1364 PetscScalar *cellCoords = NULL; 1365 const PetscScalar *array; 1366 PetscInt numCoords, cdim, d; 1367 PetscBool isDG; 1368 1369 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1370 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1371 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1372 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1373 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1374 for (p = 0; p < numCoords / cdim; ++p) { 1375 for (d = 0; d < cdim; ++d) { 1376 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1377 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1378 } 1379 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1380 if (cdim == 3) { 1381 PetscReal tmp = tcoords[1]; 1382 tcoords[1] = tcoords[2]; 1383 tcoords[2] = -tmp; 1384 } 1385 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1386 } 1387 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1388 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1389 for (d = 0; d < cdim; ++d) { 1390 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1391 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1392 } 1393 if (drawHasse) color = colors[depth % numColors]; 1394 else color = colors[rank % numColors]; 1395 for (l = 0; l < numLabels; ++l) { 1396 PetscInt val; 1397 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1398 if (val >= 0) { 1399 color = lcolors[l % numLColors]; 1400 isLabeled = PETSC_TRUE; 1401 break; 1402 } 1403 } 1404 if (drawNumbers[dim]) { 1405 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1406 } else if (drawColors[dim]) { 1407 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1408 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1409 } 1410 if (drawHasse) { 1411 int height = 0; 1412 1413 color = colors[depth % numColors]; 1414 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1418 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1419 1420 if (depth > 2) { 1421 color = colors[1 % numColors]; 1422 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1424 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1425 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1426 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1427 } 1428 1429 color = colors[1 % numColors]; 1430 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1431 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1432 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1433 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1434 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1435 1436 color = colors[0 % numColors]; 1437 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1438 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1439 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1440 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1441 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1442 1443 for (p = pStart; p < pEnd; ++p) { 1444 const PetscInt *cone; 1445 PetscInt coneSize, cp; 1446 1447 PetscCall(DMPlexGetCone(dm, p, &cone)); 1448 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1449 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1450 } 1451 } 1452 PetscCall(PetscViewerFlush(viewer)); 1453 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1454 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1455 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1456 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1457 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1458 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1459 PetscCall(PetscFree3(names, colors, lcolors)); 1460 PetscCall(PetscBTDestroy(&wp)); 1461 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1462 Vec cown, acown; 1463 VecScatter sct; 1464 ISLocalToGlobalMapping g2l; 1465 IS gid, acis; 1466 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1467 MPI_Group ggroup, ngroup; 1468 PetscScalar *array, nid; 1469 const PetscInt *idxs; 1470 PetscInt *idxs2, *start, *adjacency, *work; 1471 PetscInt64 lm[3], gm[3]; 1472 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1473 PetscMPIInt d1, d2, rank; 1474 1475 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1476 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1477 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1478 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1479 #endif 1480 if (ncomm != MPI_COMM_NULL) { 1481 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1482 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1483 d1 = 0; 1484 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1485 nid = d2; 1486 PetscCallMPI(MPI_Group_free(&ggroup)); 1487 PetscCallMPI(MPI_Group_free(&ngroup)); 1488 PetscCallMPI(MPI_Comm_free(&ncomm)); 1489 } else nid = 0.0; 1490 1491 /* Get connectivity */ 1492 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1493 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1494 1495 /* filter overlapped local cells */ 1496 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1497 PetscCall(ISGetIndices(gid, &idxs)); 1498 PetscCall(ISGetLocalSize(gid, &cum)); 1499 PetscCall(PetscMalloc1(cum, &idxs2)); 1500 for (c = cStart, cum = 0; c < cEnd; c++) { 1501 if (idxs[c - cStart] < 0) continue; 1502 idxs2[cum++] = idxs[c - cStart]; 1503 } 1504 PetscCall(ISRestoreIndices(gid, &idxs)); 1505 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1506 PetscCall(ISDestroy(&gid)); 1507 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1508 1509 /* support for node-aware cell locality */ 1510 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1511 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1512 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1513 PetscCall(VecGetArray(cown, &array)); 1514 for (c = 0; c < numVertices; c++) array[c] = nid; 1515 PetscCall(VecRestoreArray(cown, &array)); 1516 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1517 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1518 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1519 PetscCall(ISDestroy(&acis)); 1520 PetscCall(VecScatterDestroy(&sct)); 1521 PetscCall(VecDestroy(&cown)); 1522 1523 /* compute edgeCut */ 1524 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1525 PetscCall(PetscMalloc1(cum, &work)); 1526 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1527 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1528 PetscCall(ISDestroy(&gid)); 1529 PetscCall(VecGetArray(acown, &array)); 1530 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1531 PetscInt totl; 1532 1533 totl = start[c + 1] - start[c]; 1534 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1535 for (i = 0; i < totl; i++) { 1536 if (work[i] < 0) { 1537 ect += 1; 1538 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1539 } 1540 } 1541 } 1542 PetscCall(PetscFree(work)); 1543 PetscCall(VecRestoreArray(acown, &array)); 1544 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1545 lm[1] = -numVertices; 1546 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1547 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1548 lm[0] = ect; /* edgeCut */ 1549 lm[1] = ectn; /* node-aware edgeCut */ 1550 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1551 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1552 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1553 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1554 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1555 #else 1556 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1557 #endif 1558 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1559 PetscCall(PetscFree(start)); 1560 PetscCall(PetscFree(adjacency)); 1561 PetscCall(VecDestroy(&acown)); 1562 } else { 1563 const char *name; 1564 PetscInt *sizes, *hybsizes, *ghostsizes; 1565 PetscInt locDepth, depth, cellHeight, dim, d; 1566 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1567 PetscInt numLabels, l, maxSize = 17; 1568 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1569 MPI_Comm comm; 1570 PetscMPIInt size, rank; 1571 1572 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1573 PetscCallMPI(MPI_Comm_size(comm, &size)); 1574 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1575 PetscCall(DMGetDimension(dm, &dim)); 1576 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1577 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1578 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1579 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1580 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1581 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1582 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1583 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1584 gcNum = gcEnd - gcStart; 1585 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1586 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1587 for (d = 0; d <= depth; d++) { 1588 PetscInt Nc[2] = {0, 0}, ict; 1589 1590 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1591 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1592 ict = ct0; 1593 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1594 ct0 = (DMPolytopeType)ict; 1595 for (p = pStart; p < pEnd; ++p) { 1596 DMPolytopeType ct; 1597 1598 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1599 if (ct == ct0) ++Nc[0]; 1600 else ++Nc[1]; 1601 } 1602 if (size < maxSize) { 1603 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1604 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1605 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1606 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1607 for (p = 0; p < size; ++p) { 1608 if (rank == 0) { 1609 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1610 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1611 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1612 } 1613 } 1614 } else { 1615 PetscInt locMinMax[2]; 1616 1617 locMinMax[0] = Nc[0] + Nc[1]; 1618 locMinMax[1] = Nc[0] + Nc[1]; 1619 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1620 locMinMax[0] = Nc[1]; 1621 locMinMax[1] = Nc[1]; 1622 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1623 if (d == depth) { 1624 locMinMax[0] = gcNum; 1625 locMinMax[1] = gcNum; 1626 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1627 } 1628 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1629 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1630 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1631 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1632 } 1633 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1634 } 1635 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1636 { 1637 const PetscReal *maxCell; 1638 const PetscReal *L; 1639 PetscBool localized; 1640 1641 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1642 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1643 if (L || localized) { 1644 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1645 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1646 if (L) { 1647 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1648 for (d = 0; d < dim; ++d) { 1649 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1650 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1651 } 1652 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1653 } 1654 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1655 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1656 } 1657 } 1658 PetscCall(DMGetNumLabels(dm, &numLabels)); 1659 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1660 for (l = 0; l < numLabels; ++l) { 1661 DMLabel label; 1662 const char *name; 1663 PetscInt *values; 1664 PetscInt numValues, v; 1665 1666 PetscCall(DMGetLabelName(dm, l, &name)); 1667 PetscCall(DMGetLabel(dm, name, &label)); 1668 PetscCall(DMLabelGetNumValues(label, &numValues)); 1669 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1670 1671 { // Extract array of DMLabel values so it can be sorted 1672 IS is_values; 1673 const PetscInt *is_values_local = NULL; 1674 1675 PetscCall(DMLabelGetValueIS(label, &is_values)); 1676 PetscCall(ISGetIndices(is_values, &is_values_local)); 1677 PetscCall(PetscMalloc1(numValues, &values)); 1678 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1679 PetscCall(PetscSortInt(numValues, values)); 1680 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1681 PetscCall(ISDestroy(&is_values)); 1682 } 1683 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1684 for (v = 0; v < numValues; ++v) { 1685 PetscInt size; 1686 1687 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1688 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1689 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1690 } 1691 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1692 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1693 PetscCall(PetscFree(values)); 1694 } 1695 { 1696 char **labelNames; 1697 PetscInt Nl = numLabels; 1698 PetscBool flg; 1699 1700 PetscCall(PetscMalloc1(Nl, &labelNames)); 1701 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1702 for (l = 0; l < Nl; ++l) { 1703 DMLabel label; 1704 1705 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1706 if (flg) { 1707 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1708 PetscCall(DMLabelView(label, viewer)); 1709 } 1710 PetscCall(PetscFree(labelNames[l])); 1711 } 1712 PetscCall(PetscFree(labelNames)); 1713 } 1714 /* If no fields are specified, people do not want to see adjacency */ 1715 if (dm->Nf) { 1716 PetscInt f; 1717 1718 for (f = 0; f < dm->Nf; ++f) { 1719 const char *name; 1720 1721 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1722 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1723 PetscCall(PetscViewerASCIIPushTab(viewer)); 1724 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1725 if (dm->fields[f].adjacency[0]) { 1726 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1727 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1728 } else { 1729 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1730 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1731 } 1732 PetscCall(PetscViewerASCIIPopTab(viewer)); 1733 } 1734 } 1735 PetscCall(DMGetCoarseDM(dm, &cdm)); 1736 if (cdm) { 1737 PetscCall(PetscViewerASCIIPushTab(viewer)); 1738 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1739 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1740 PetscCall(PetscViewerASCIIPopTab(viewer)); 1741 } 1742 } 1743 PetscFunctionReturn(PETSC_SUCCESS); 1744 } 1745 1746 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1747 { 1748 DMPolytopeType ct; 1749 PetscMPIInt rank; 1750 PetscInt cdim; 1751 1752 PetscFunctionBegin; 1753 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1754 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1755 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1756 switch (ct) { 1757 case DM_POLYTOPE_SEGMENT: 1758 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1759 switch (cdim) { 1760 case 1: { 1761 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1762 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1763 1764 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1765 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1766 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1767 } break; 1768 case 2: { 1769 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1770 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1771 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1772 1773 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1774 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)); 1775 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)); 1776 } break; 1777 default: 1778 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1779 } 1780 break; 1781 case DM_POLYTOPE_TRIANGLE: 1782 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)); 1783 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1784 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1785 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1786 break; 1787 case DM_POLYTOPE_QUADRILATERAL: 1788 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)); 1789 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)); 1790 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1791 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1792 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1793 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1794 break; 1795 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1796 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)); 1797 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)); 1798 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1799 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1800 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1801 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1802 break; 1803 case DM_POLYTOPE_FV_GHOST: 1804 break; 1805 default: 1806 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1807 } 1808 PetscFunctionReturn(PETSC_SUCCESS); 1809 } 1810 1811 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1812 { 1813 PetscReal centroid[2] = {0., 0.}; 1814 PetscMPIInt rank; 1815 PetscMPIInt fillColor; 1816 1817 PetscFunctionBegin; 1818 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1819 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1820 for (PetscInt v = 0; v < Nv; ++v) { 1821 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1822 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1823 } 1824 for (PetscInt e = 0; e < Nv; ++e) { 1825 refCoords[0] = refVertices[e * 2 + 0]; 1826 refCoords[1] = refVertices[e * 2 + 1]; 1827 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1828 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1829 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1830 } 1831 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1832 for (PetscInt d = 0; d < edgeDiv; ++d) { 1833 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)); 1834 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1835 } 1836 } 1837 PetscFunctionReturn(PETSC_SUCCESS); 1838 } 1839 1840 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1841 { 1842 DMPolytopeType ct; 1843 1844 PetscFunctionBegin; 1845 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1846 switch (ct) { 1847 case DM_POLYTOPE_TRIANGLE: { 1848 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1849 1850 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1851 } break; 1852 case DM_POLYTOPE_QUADRILATERAL: { 1853 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1854 1855 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1856 } break; 1857 default: 1858 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1859 } 1860 PetscFunctionReturn(PETSC_SUCCESS); 1861 } 1862 1863 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1864 { 1865 PetscDraw draw; 1866 DM cdm; 1867 PetscSection coordSection; 1868 Vec coordinates; 1869 PetscReal xyl[3], xyr[3]; 1870 PetscReal *refCoords, *edgeCoords; 1871 PetscBool isnull, drawAffine; 1872 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1873 1874 PetscFunctionBegin; 1875 PetscCall(DMGetCoordinateDim(dm, &dim)); 1876 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1877 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1878 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1879 edgeDiv = cDegree + 1; 1880 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1881 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1882 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1883 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1884 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1885 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1886 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1887 1888 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1889 PetscCall(PetscDrawIsNull(draw, &isnull)); 1890 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1891 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1892 1893 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1894 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1895 PetscCall(PetscDrawClear(draw)); 1896 1897 for (c = cStart; c < cEnd; ++c) { 1898 PetscScalar *coords = NULL; 1899 const PetscScalar *coords_arr; 1900 PetscInt numCoords; 1901 PetscBool isDG; 1902 1903 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1904 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1905 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1906 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1907 } 1908 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1909 PetscCall(PetscDrawFlush(draw)); 1910 PetscCall(PetscDrawPause(draw)); 1911 PetscCall(PetscDrawSave(draw)); 1912 PetscFunctionReturn(PETSC_SUCCESS); 1913 } 1914 1915 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1916 { 1917 DM odm = dm, rdm = dm, cdm; 1918 PetscFE fe; 1919 PetscSpace sp; 1920 PetscClassId id; 1921 PetscInt degree; 1922 PetscBool hoView = PETSC_TRUE; 1923 1924 PetscFunctionBegin; 1925 PetscObjectOptionsBegin((PetscObject)dm); 1926 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1927 PetscOptionsEnd(); 1928 PetscCall(PetscObjectReference((PetscObject)dm)); 1929 *hdm = dm; 1930 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1931 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1932 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1933 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1934 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1935 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1936 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1937 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1938 DM cdm, rcdm; 1939 Mat In; 1940 Vec cl, rcl; 1941 1942 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1943 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1944 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1945 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1946 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1947 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1948 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1949 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1950 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1951 PetscCall(MatMult(In, cl, rcl)); 1952 PetscCall(MatDestroy(&In)); 1953 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1954 PetscCall(DMDestroy(&odm)); 1955 odm = rdm; 1956 } 1957 *hdm = rdm; 1958 PetscFunctionReturn(PETSC_SUCCESS); 1959 } 1960 1961 #if defined(PETSC_HAVE_EXODUSII) 1962 #include <exodusII.h> 1963 #include <petscviewerexodusii.h> 1964 #endif 1965 1966 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1967 { 1968 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1969 char name[PETSC_MAX_PATH_LEN]; 1970 1971 PetscFunctionBegin; 1972 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1973 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1974 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1975 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1976 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1977 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1978 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1979 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1980 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1981 if (iascii) { 1982 PetscViewerFormat format; 1983 PetscCall(PetscViewerGetFormat(viewer, &format)); 1984 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1985 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1986 } else if (ishdf5) { 1987 #if defined(PETSC_HAVE_HDF5) 1988 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1989 #else 1990 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1991 #endif 1992 } else if (isvtk) { 1993 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1994 } else if (isdraw) { 1995 DM hdm; 1996 1997 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1998 PetscCall(DMPlexView_Draw(hdm, viewer)); 1999 PetscCall(DMDestroy(&hdm)); 2000 } else if (isglvis) { 2001 PetscCall(DMPlexView_GLVis(dm, viewer)); 2002 #if defined(PETSC_HAVE_EXODUSII) 2003 } else if (isexodus) { 2004 /* 2005 exodusII requires that all sets be part of exactly one cell set. 2006 If the dm does not have a "Cell Sets" label defined, we create one 2007 with ID 1, containing all cells. 2008 Note that if the Cell Sets label is defined but does not cover all cells, 2009 we may still have a problem. This should probably be checked here or in the viewer; 2010 */ 2011 PetscInt numCS; 2012 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2013 if (!numCS) { 2014 PetscInt cStart, cEnd, c; 2015 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2016 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2017 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2018 } 2019 PetscCall(DMView_PlexExodusII(dm, viewer)); 2020 #endif 2021 #if defined(PETSC_HAVE_CGNS) 2022 } else if (iscgns) { 2023 PetscCall(DMView_PlexCGNS(dm, viewer)); 2024 #endif 2025 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2026 /* Optionally view the partition */ 2027 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2028 if (flg) { 2029 Vec ranks; 2030 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2031 PetscCall(VecView(ranks, viewer)); 2032 PetscCall(VecDestroy(&ranks)); 2033 } 2034 /* Optionally view a label */ 2035 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2036 if (flg) { 2037 DMLabel label; 2038 Vec val; 2039 2040 PetscCall(DMGetLabel(dm, name, &label)); 2041 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2042 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2043 PetscCall(VecView(val, viewer)); 2044 PetscCall(VecDestroy(&val)); 2045 } 2046 PetscFunctionReturn(PETSC_SUCCESS); 2047 } 2048 2049 /*@ 2050 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2051 2052 Collective 2053 2054 Input Parameters: 2055 + dm - The `DM` whose topology is to be saved 2056 - viewer - The `PetscViewer` to save it in 2057 2058 Level: advanced 2059 2060 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2061 @*/ 2062 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2063 { 2064 PetscBool ishdf5; 2065 2066 PetscFunctionBegin; 2067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2068 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2069 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2070 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2071 if (ishdf5) { 2072 #if defined(PETSC_HAVE_HDF5) 2073 PetscViewerFormat format; 2074 PetscCall(PetscViewerGetFormat(viewer, &format)); 2075 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2076 IS globalPointNumbering; 2077 2078 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2079 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2080 PetscCall(ISDestroy(&globalPointNumbering)); 2081 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2082 #else 2083 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2084 #endif 2085 } 2086 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2087 PetscFunctionReturn(PETSC_SUCCESS); 2088 } 2089 2090 /*@ 2091 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2092 2093 Collective 2094 2095 Input Parameters: 2096 + dm - The `DM` whose coordinates are to be saved 2097 - viewer - The `PetscViewer` for saving 2098 2099 Level: advanced 2100 2101 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2102 @*/ 2103 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2104 { 2105 PetscBool ishdf5; 2106 2107 PetscFunctionBegin; 2108 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2109 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2110 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2111 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2112 if (ishdf5) { 2113 #if defined(PETSC_HAVE_HDF5) 2114 PetscViewerFormat format; 2115 PetscCall(PetscViewerGetFormat(viewer, &format)); 2116 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2117 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2118 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2119 #else 2120 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2121 #endif 2122 } 2123 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2124 PetscFunctionReturn(PETSC_SUCCESS); 2125 } 2126 2127 /*@ 2128 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2129 2130 Collective 2131 2132 Input Parameters: 2133 + dm - The `DM` whose labels are to be saved 2134 - viewer - The `PetscViewer` for saving 2135 2136 Level: advanced 2137 2138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2139 @*/ 2140 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2141 { 2142 PetscBool ishdf5; 2143 2144 PetscFunctionBegin; 2145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2146 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2147 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2148 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2149 if (ishdf5) { 2150 #if defined(PETSC_HAVE_HDF5) 2151 IS globalPointNumbering; 2152 PetscViewerFormat format; 2153 2154 PetscCall(PetscViewerGetFormat(viewer, &format)); 2155 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2156 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2157 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2158 PetscCall(ISDestroy(&globalPointNumbering)); 2159 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2160 #else 2161 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2162 #endif 2163 } 2164 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2165 PetscFunctionReturn(PETSC_SUCCESS); 2166 } 2167 2168 /*@ 2169 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2170 2171 Collective 2172 2173 Input Parameters: 2174 + dm - The `DM` that contains the topology on which the section to be saved is defined 2175 . viewer - The `PetscViewer` for saving 2176 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2177 2178 Level: advanced 2179 2180 Notes: 2181 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. 2182 2183 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. 2184 2185 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2186 @*/ 2187 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2188 { 2189 PetscBool ishdf5; 2190 2191 PetscFunctionBegin; 2192 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2193 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2194 if (!sectiondm) sectiondm = dm; 2195 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2196 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2197 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2198 if (ishdf5) { 2199 #if defined(PETSC_HAVE_HDF5) 2200 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2201 #else 2202 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2203 #endif 2204 } 2205 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2206 PetscFunctionReturn(PETSC_SUCCESS); 2207 } 2208 2209 /*@ 2210 DMPlexGlobalVectorView - Saves a global vector 2211 2212 Collective 2213 2214 Input Parameters: 2215 + dm - The `DM` that represents the topology 2216 . viewer - The `PetscViewer` to save data with 2217 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2218 - vec - The global vector to be saved 2219 2220 Level: advanced 2221 2222 Notes: 2223 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. 2224 2225 Calling sequence: 2226 .vb 2227 DMCreate(PETSC_COMM_WORLD, &dm); 2228 DMSetType(dm, DMPLEX); 2229 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2230 DMClone(dm, §iondm); 2231 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2232 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2233 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2234 PetscSectionSetChart(section, pStart, pEnd); 2235 PetscSectionSetUp(section); 2236 DMSetLocalSection(sectiondm, section); 2237 PetscSectionDestroy(§ion); 2238 DMGetGlobalVector(sectiondm, &vec); 2239 PetscObjectSetName((PetscObject)vec, "vec_name"); 2240 DMPlexTopologyView(dm, viewer); 2241 DMPlexSectionView(dm, viewer, sectiondm); 2242 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2243 DMRestoreGlobalVector(sectiondm, &vec); 2244 DMDestroy(§iondm); 2245 DMDestroy(&dm); 2246 .ve 2247 2248 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2249 @*/ 2250 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2251 { 2252 PetscBool ishdf5; 2253 2254 PetscFunctionBegin; 2255 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2256 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2257 if (!sectiondm) sectiondm = dm; 2258 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2259 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2260 /* Check consistency */ 2261 { 2262 PetscSection section; 2263 PetscBool includesConstraints; 2264 PetscInt m, m1; 2265 2266 PetscCall(VecGetLocalSize(vec, &m1)); 2267 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2268 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2269 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2270 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2271 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2272 } 2273 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2274 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2275 if (ishdf5) { 2276 #if defined(PETSC_HAVE_HDF5) 2277 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2278 #else 2279 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2280 #endif 2281 } 2282 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2283 PetscFunctionReturn(PETSC_SUCCESS); 2284 } 2285 2286 /*@ 2287 DMPlexLocalVectorView - Saves a local vector 2288 2289 Collective 2290 2291 Input Parameters: 2292 + dm - The `DM` that represents the topology 2293 . viewer - The `PetscViewer` to save data with 2294 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2295 - vec - The local vector to be saved 2296 2297 Level: advanced 2298 2299 Note: 2300 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. 2301 2302 Calling sequence: 2303 .vb 2304 DMCreate(PETSC_COMM_WORLD, &dm); 2305 DMSetType(dm, DMPLEX); 2306 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2307 DMClone(dm, §iondm); 2308 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2309 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2310 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2311 PetscSectionSetChart(section, pStart, pEnd); 2312 PetscSectionSetUp(section); 2313 DMSetLocalSection(sectiondm, section); 2314 DMGetLocalVector(sectiondm, &vec); 2315 PetscObjectSetName((PetscObject)vec, "vec_name"); 2316 DMPlexTopologyView(dm, viewer); 2317 DMPlexSectionView(dm, viewer, sectiondm); 2318 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2319 DMRestoreLocalVector(sectiondm, &vec); 2320 DMDestroy(§iondm); 2321 DMDestroy(&dm); 2322 .ve 2323 2324 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2325 @*/ 2326 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2327 { 2328 PetscBool ishdf5; 2329 2330 PetscFunctionBegin; 2331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2332 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2333 if (!sectiondm) sectiondm = dm; 2334 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2335 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2336 /* Check consistency */ 2337 { 2338 PetscSection section; 2339 PetscBool includesConstraints; 2340 PetscInt m, m1; 2341 2342 PetscCall(VecGetLocalSize(vec, &m1)); 2343 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2344 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2345 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2346 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2347 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2348 } 2349 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2350 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2351 if (ishdf5) { 2352 #if defined(PETSC_HAVE_HDF5) 2353 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2354 #else 2355 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2356 #endif 2357 } 2358 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2359 PetscFunctionReturn(PETSC_SUCCESS); 2360 } 2361 2362 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2363 { 2364 PetscBool ishdf5; 2365 2366 PetscFunctionBegin; 2367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2368 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2369 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2370 if (ishdf5) { 2371 #if defined(PETSC_HAVE_HDF5) 2372 PetscViewerFormat format; 2373 PetscCall(PetscViewerGetFormat(viewer, &format)); 2374 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2375 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2376 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2377 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2378 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2379 PetscFunctionReturn(PETSC_SUCCESS); 2380 #else 2381 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2382 #endif 2383 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2384 } 2385 2386 /*@ 2387 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2388 2389 Collective 2390 2391 Input Parameters: 2392 + dm - The `DM` into which the topology is loaded 2393 - viewer - The `PetscViewer` for the saved topology 2394 2395 Output Parameter: 2396 . 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; 2397 `NULL` if unneeded 2398 2399 Level: advanced 2400 2401 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2402 `PetscViewer`, `PetscSF` 2403 @*/ 2404 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2405 { 2406 PetscBool ishdf5; 2407 2408 PetscFunctionBegin; 2409 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2410 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2411 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2412 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2413 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2414 if (ishdf5) { 2415 #if defined(PETSC_HAVE_HDF5) 2416 PetscViewerFormat format; 2417 PetscCall(PetscViewerGetFormat(viewer, &format)); 2418 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2419 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2420 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2421 #else 2422 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2423 #endif 2424 } 2425 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2426 PetscFunctionReturn(PETSC_SUCCESS); 2427 } 2428 2429 /*@ 2430 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2431 2432 Collective 2433 2434 Input Parameters: 2435 + dm - The `DM` into which the coordinates are loaded 2436 . viewer - The `PetscViewer` for the saved coordinates 2437 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2438 2439 Level: advanced 2440 2441 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2442 `PetscSF`, `PetscViewer` 2443 @*/ 2444 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2445 { 2446 PetscBool ishdf5; 2447 2448 PetscFunctionBegin; 2449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2450 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2451 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2452 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2453 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2454 if (ishdf5) { 2455 #if defined(PETSC_HAVE_HDF5) 2456 PetscViewerFormat format; 2457 PetscCall(PetscViewerGetFormat(viewer, &format)); 2458 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2459 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2460 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2461 #else 2462 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2463 #endif 2464 } 2465 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2466 PetscFunctionReturn(PETSC_SUCCESS); 2467 } 2468 2469 /*@ 2470 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2471 2472 Collective 2473 2474 Input Parameters: 2475 + dm - The `DM` into which the labels are loaded 2476 . viewer - The `PetscViewer` for the saved labels 2477 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2478 2479 Level: advanced 2480 2481 Note: 2482 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2483 2484 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2485 `PetscSF`, `PetscViewer` 2486 @*/ 2487 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2488 { 2489 PetscBool ishdf5; 2490 2491 PetscFunctionBegin; 2492 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2493 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2494 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2495 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2496 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2497 if (ishdf5) { 2498 #if defined(PETSC_HAVE_HDF5) 2499 PetscViewerFormat format; 2500 2501 PetscCall(PetscViewerGetFormat(viewer, &format)); 2502 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2503 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2504 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2505 #else 2506 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2507 #endif 2508 } 2509 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2510 PetscFunctionReturn(PETSC_SUCCESS); 2511 } 2512 2513 /*@ 2514 DMPlexSectionLoad - Loads section into a `DMPLEX` 2515 2516 Collective 2517 2518 Input Parameters: 2519 + dm - The `DM` that represents the topology 2520 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2521 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2522 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2523 2524 Output Parameters: 2525 + 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) 2526 - 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) 2527 2528 Level: advanced 2529 2530 Notes: 2531 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. 2532 2533 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. 2534 2535 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. 2536 2537 Example using 2 processes: 2538 .vb 2539 NX (number of points on dm): 4 2540 sectionA : the on-disk section 2541 vecA : a vector associated with sectionA 2542 sectionB : sectiondm's local section constructed in this function 2543 vecB (local) : a vector associated with sectiondm's local section 2544 vecB (global) : a vector associated with sectiondm's global section 2545 2546 rank 0 rank 1 2547 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2548 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2549 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2550 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2551 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2552 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2553 sectionB->atlasDof : 1 0 1 | 1 3 2554 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2555 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2556 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2557 .ve 2558 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2559 2560 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2561 @*/ 2562 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2563 { 2564 PetscBool ishdf5; 2565 2566 PetscFunctionBegin; 2567 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2568 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2569 if (!sectiondm) sectiondm = dm; 2570 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2571 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2572 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2573 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2574 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2575 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2576 if (ishdf5) { 2577 #if defined(PETSC_HAVE_HDF5) 2578 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2579 #else 2580 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2581 #endif 2582 } 2583 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2584 PetscFunctionReturn(PETSC_SUCCESS); 2585 } 2586 2587 /*@ 2588 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2589 2590 Collective 2591 2592 Input Parameters: 2593 + dm - The `DM` that represents the topology 2594 . viewer - The `PetscViewer` that represents the on-disk vector data 2595 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2596 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2597 - vec - The global vector to set values of 2598 2599 Level: advanced 2600 2601 Notes: 2602 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. 2603 2604 Calling sequence: 2605 .vb 2606 DMCreate(PETSC_COMM_WORLD, &dm); 2607 DMSetType(dm, DMPLEX); 2608 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2609 DMPlexTopologyLoad(dm, viewer, &sfX); 2610 DMClone(dm, §iondm); 2611 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2612 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2613 DMGetGlobalVector(sectiondm, &vec); 2614 PetscObjectSetName((PetscObject)vec, "vec_name"); 2615 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2616 DMRestoreGlobalVector(sectiondm, &vec); 2617 PetscSFDestroy(&gsf); 2618 PetscSFDestroy(&sfX); 2619 DMDestroy(§iondm); 2620 DMDestroy(&dm); 2621 .ve 2622 2623 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2624 `PetscSF`, `PetscViewer` 2625 @*/ 2626 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2627 { 2628 PetscBool ishdf5; 2629 2630 PetscFunctionBegin; 2631 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2632 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2633 if (!sectiondm) sectiondm = dm; 2634 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2635 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2636 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2637 /* Check consistency */ 2638 { 2639 PetscSection section; 2640 PetscBool includesConstraints; 2641 PetscInt m, m1; 2642 2643 PetscCall(VecGetLocalSize(vec, &m1)); 2644 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2645 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2646 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2647 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2648 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2649 } 2650 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2651 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2652 if (ishdf5) { 2653 #if defined(PETSC_HAVE_HDF5) 2654 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2655 #else 2656 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2657 #endif 2658 } 2659 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2660 PetscFunctionReturn(PETSC_SUCCESS); 2661 } 2662 2663 /*@ 2664 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2665 2666 Collective 2667 2668 Input Parameters: 2669 + dm - The `DM` that represents the topology 2670 . viewer - The `PetscViewer` that represents the on-disk vector data 2671 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2672 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2673 - vec - The local vector to set values of 2674 2675 Level: advanced 2676 2677 Notes: 2678 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. 2679 2680 Calling sequence: 2681 .vb 2682 DMCreate(PETSC_COMM_WORLD, &dm); 2683 DMSetType(dm, DMPLEX); 2684 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2685 DMPlexTopologyLoad(dm, viewer, &sfX); 2686 DMClone(dm, §iondm); 2687 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2688 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2689 DMGetLocalVector(sectiondm, &vec); 2690 PetscObjectSetName((PetscObject)vec, "vec_name"); 2691 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2692 DMRestoreLocalVector(sectiondm, &vec); 2693 PetscSFDestroy(&lsf); 2694 PetscSFDestroy(&sfX); 2695 DMDestroy(§iondm); 2696 DMDestroy(&dm); 2697 .ve 2698 2699 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2700 `PetscSF`, `PetscViewer` 2701 @*/ 2702 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2703 { 2704 PetscBool ishdf5; 2705 2706 PetscFunctionBegin; 2707 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2708 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2709 if (!sectiondm) sectiondm = dm; 2710 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2711 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2712 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2713 /* Check consistency */ 2714 { 2715 PetscSection section; 2716 PetscBool includesConstraints; 2717 PetscInt m, m1; 2718 2719 PetscCall(VecGetLocalSize(vec, &m1)); 2720 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2721 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2722 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2723 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2724 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2725 } 2726 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2727 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2728 if (ishdf5) { 2729 #if defined(PETSC_HAVE_HDF5) 2730 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2731 #else 2732 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2733 #endif 2734 } 2735 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2736 PetscFunctionReturn(PETSC_SUCCESS); 2737 } 2738 2739 PetscErrorCode DMDestroy_Plex(DM dm) 2740 { 2741 DM_Plex *mesh = (DM_Plex *)dm->data; 2742 2743 PetscFunctionBegin; 2744 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2745 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2746 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2747 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2748 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2749 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2750 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2751 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2752 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2753 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2754 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2755 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2756 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2757 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2758 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2759 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2760 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2761 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2762 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2763 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2764 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2765 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2766 PetscCall(PetscFree(mesh->cones)); 2767 PetscCall(PetscFree(mesh->coneOrientations)); 2768 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2769 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2770 PetscCall(PetscFree(mesh->supports)); 2771 PetscCall(PetscFree(mesh->cellTypes)); 2772 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2773 PetscCall(PetscFree(mesh->tetgenOpts)); 2774 PetscCall(PetscFree(mesh->triangleOpts)); 2775 PetscCall(PetscFree(mesh->transformType)); 2776 PetscCall(PetscFree(mesh->distributionName)); 2777 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2778 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2779 PetscCall(ISDestroy(&mesh->subpointIS)); 2780 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2781 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2782 if (mesh->periodic.face_sfs) { 2783 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2784 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2785 } 2786 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2787 if (mesh->periodic.periodic_points) { 2788 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2789 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2790 } 2791 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2792 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2793 PetscCall(ISDestroy(&mesh->anchorIS)); 2794 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2795 PetscCall(PetscFree(mesh->parents)); 2796 PetscCall(PetscFree(mesh->childIDs)); 2797 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2798 PetscCall(PetscFree(mesh->children)); 2799 PetscCall(DMDestroy(&mesh->referenceTree)); 2800 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2801 PetscCall(PetscFree(mesh->neighbors)); 2802 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2803 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2804 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2805 PetscCall(PetscFree(mesh)); 2806 PetscFunctionReturn(PETSC_SUCCESS); 2807 } 2808 2809 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2810 { 2811 PetscSection sectionGlobal, sectionLocal; 2812 PetscInt bs = -1, mbs; 2813 PetscInt localSize, localStart = 0; 2814 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2815 MatType mtype; 2816 ISLocalToGlobalMapping ltog; 2817 2818 PetscFunctionBegin; 2819 PetscCall(MatInitializePackage()); 2820 mtype = dm->mattype; 2821 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2822 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2823 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2824 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2825 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2826 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2827 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2828 PetscCall(MatSetType(*J, mtype)); 2829 PetscCall(MatSetFromOptions(*J)); 2830 PetscCall(MatGetBlockSize(*J, &mbs)); 2831 if (mbs > 1) bs = mbs; 2832 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2833 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2834 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2835 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2836 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2837 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2838 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2839 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2840 if (!isShell) { 2841 // There are three states with pblocks, since block starts can have no dofs: 2842 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2843 // TRUE) Block Start: The first entry in a block has been added 2844 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2845 PetscBT blst; 2846 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2847 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2848 const PetscInt *perm = NULL; 2849 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2850 PetscInt pStart, pEnd, dof, cdof, num_fields; 2851 2852 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2853 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2854 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2855 2856 PetscCall(PetscCalloc1(localSize, &pblocks)); 2857 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2858 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2859 // We need to process in the permuted order to get block sizes right 2860 for (PetscInt point = pStart; point < pEnd; ++point) { 2861 const PetscInt p = perm ? perm[point] : point; 2862 2863 switch (dm->blocking_type) { 2864 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2865 PetscInt bdof, offset; 2866 2867 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2868 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2869 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2870 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2871 if (dof > 0) { 2872 // State change 2873 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2874 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2875 2876 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2877 // Signal block concatenation 2878 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2879 } 2880 dof = dof < 0 ? -(dof + 1) : dof; 2881 bdof = cdof && (dof - cdof) ? 1 : dof; 2882 if (dof) { 2883 if (bs < 0) { 2884 bs = bdof; 2885 } else if (bs != bdof) { 2886 bs = 1; 2887 } 2888 } 2889 } break; 2890 case DM_BLOCKING_FIELD_NODE: { 2891 for (PetscInt field = 0; field < num_fields; field++) { 2892 PetscInt num_comp, bdof, offset; 2893 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2894 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2895 if (dof < 0) continue; 2896 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2897 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2898 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); 2899 PetscInt num_nodes = dof / num_comp; 2900 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2901 // Handle possibly constant block size (unlikely) 2902 bdof = cdof && (dof - cdof) ? 1 : dof; 2903 if (dof) { 2904 if (bs < 0) { 2905 bs = bdof; 2906 } else if (bs != bdof) { 2907 bs = 1; 2908 } 2909 } 2910 } 2911 } break; 2912 } 2913 } 2914 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2915 /* Must have same blocksize on all procs (some might have no points) */ 2916 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2917 bsLocal[1] = bs; 2918 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2919 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2920 else bs = bsMinMax[0]; 2921 bs = PetscMax(1, bs); 2922 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2923 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2924 PetscCall(MatSetBlockSize(*J, bs)); 2925 PetscCall(MatSetUp(*J)); 2926 } else { 2927 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2928 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2929 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2930 } 2931 if (pblocks) { // Consolidate blocks 2932 PetscInt nblocks = 0; 2933 pblocks[0] = PetscAbs(pblocks[0]); 2934 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2935 if (pblocks[i] == 0) continue; 2936 // Negative block size indicates the blocks should be concatenated 2937 if (pblocks[i] < 0) { 2938 pblocks[i] = -pblocks[i]; 2939 pblocks[nblocks - 1] += pblocks[i]; 2940 } else { 2941 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2942 } 2943 for (PetscInt j = 1; j < pblocks[i]; j++) 2944 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); 2945 } 2946 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2947 } 2948 PetscCall(PetscFree(pblocks)); 2949 } 2950 PetscCall(MatSetDM(*J, dm)); 2951 PetscFunctionReturn(PETSC_SUCCESS); 2952 } 2953 2954 /*@ 2955 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2956 2957 Not Collective 2958 2959 Input Parameter: 2960 . dm - The `DMPLEX` 2961 2962 Output Parameter: 2963 . subsection - The subdomain section 2964 2965 Level: developer 2966 2967 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2968 @*/ 2969 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2970 { 2971 DM_Plex *mesh = (DM_Plex *)dm->data; 2972 2973 PetscFunctionBegin; 2974 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2975 if (!mesh->subdomainSection) { 2976 PetscSection section; 2977 PetscSF sf; 2978 2979 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2980 PetscCall(DMGetLocalSection(dm, §ion)); 2981 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2982 PetscCall(PetscSFDestroy(&sf)); 2983 } 2984 *subsection = mesh->subdomainSection; 2985 PetscFunctionReturn(PETSC_SUCCESS); 2986 } 2987 2988 /*@ 2989 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2990 2991 Not Collective 2992 2993 Input Parameter: 2994 . dm - The `DMPLEX` 2995 2996 Output Parameters: 2997 + pStart - The first mesh point 2998 - pEnd - The upper bound for mesh points 2999 3000 Level: beginner 3001 3002 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3003 @*/ 3004 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3005 { 3006 DM_Plex *mesh = (DM_Plex *)dm->data; 3007 3008 PetscFunctionBegin; 3009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3010 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3011 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3012 PetscFunctionReturn(PETSC_SUCCESS); 3013 } 3014 3015 /*@ 3016 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3017 3018 Not Collective 3019 3020 Input Parameters: 3021 + dm - The `DMPLEX` 3022 . pStart - The first mesh point 3023 - pEnd - The upper bound for mesh points 3024 3025 Level: beginner 3026 3027 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3028 @*/ 3029 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3030 { 3031 DM_Plex *mesh = (DM_Plex *)dm->data; 3032 3033 PetscFunctionBegin; 3034 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3035 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3036 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3037 PetscCall(PetscFree(mesh->cellTypes)); 3038 PetscFunctionReturn(PETSC_SUCCESS); 3039 } 3040 3041 /*@ 3042 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3043 3044 Not Collective 3045 3046 Input Parameters: 3047 + dm - The `DMPLEX` 3048 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3049 3050 Output Parameter: 3051 . size - The cone size for point `p` 3052 3053 Level: beginner 3054 3055 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3056 @*/ 3057 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3058 { 3059 DM_Plex *mesh = (DM_Plex *)dm->data; 3060 3061 PetscFunctionBegin; 3062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3063 PetscAssertPointer(size, 3); 3064 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3065 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3066 PetscFunctionReturn(PETSC_SUCCESS); 3067 } 3068 3069 /*@ 3070 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3071 3072 Not Collective 3073 3074 Input Parameters: 3075 + dm - The `DMPLEX` 3076 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3077 - size - The cone size for point `p` 3078 3079 Level: beginner 3080 3081 Note: 3082 This should be called after `DMPlexSetChart()`. 3083 3084 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3085 @*/ 3086 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3087 { 3088 DM_Plex *mesh = (DM_Plex *)dm->data; 3089 3090 PetscFunctionBegin; 3091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3092 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3093 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3094 PetscFunctionReturn(PETSC_SUCCESS); 3095 } 3096 3097 /*@C 3098 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3099 3100 Not Collective 3101 3102 Input Parameters: 3103 + dm - The `DMPLEX` 3104 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3105 3106 Output Parameter: 3107 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3108 3109 Level: beginner 3110 3111 Fortran Notes: 3112 `cone` must be declared with 3113 .vb 3114 PetscInt, pointer :: cone(:) 3115 .ve 3116 3117 You must also call `DMPlexRestoreCone()` after you finish using the array. 3118 `DMPlexRestoreCone()` is not needed/available in C. 3119 3120 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3121 @*/ 3122 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3123 { 3124 DM_Plex *mesh = (DM_Plex *)dm->data; 3125 PetscInt off; 3126 3127 PetscFunctionBegin; 3128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3129 PetscAssertPointer(cone, 3); 3130 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3131 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3132 PetscFunctionReturn(PETSC_SUCCESS); 3133 } 3134 3135 /*@ 3136 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3137 3138 Not Collective 3139 3140 Input Parameters: 3141 + dm - The `DMPLEX` 3142 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3143 3144 Output Parameters: 3145 + pConesSection - `PetscSection` describing the layout of `pCones` 3146 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3147 3148 Level: intermediate 3149 3150 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3151 @*/ 3152 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3153 { 3154 PetscSection cs, newcs; 3155 PetscInt *cones; 3156 PetscInt *newarr = NULL; 3157 PetscInt n; 3158 3159 PetscFunctionBegin; 3160 PetscCall(DMPlexGetCones(dm, &cones)); 3161 PetscCall(DMPlexGetConeSection(dm, &cs)); 3162 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3163 if (pConesSection) *pConesSection = newcs; 3164 if (pCones) { 3165 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3166 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3167 } 3168 PetscFunctionReturn(PETSC_SUCCESS); 3169 } 3170 3171 /*@ 3172 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3173 3174 Not Collective 3175 3176 Input Parameters: 3177 + dm - The `DMPLEX` 3178 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3179 3180 Output Parameter: 3181 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3182 3183 Level: advanced 3184 3185 Notes: 3186 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3187 3188 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3189 3190 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3191 `DMPlexGetDepth()`, `IS` 3192 @*/ 3193 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3194 { 3195 IS *expandedPointsAll; 3196 PetscInt depth; 3197 3198 PetscFunctionBegin; 3199 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3200 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3201 PetscAssertPointer(expandedPoints, 3); 3202 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3203 *expandedPoints = expandedPointsAll[0]; 3204 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3205 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3206 PetscFunctionReturn(PETSC_SUCCESS); 3207 } 3208 3209 /*@ 3210 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3211 (DAG points of depth 0, i.e., without cones). 3212 3213 Not Collective 3214 3215 Input Parameters: 3216 + dm - The `DMPLEX` 3217 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3218 3219 Output Parameters: 3220 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3221 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3222 - sections - (optional) An array of sections which describe mappings from points to their cone points 3223 3224 Level: advanced 3225 3226 Notes: 3227 Like `DMPlexGetConeTuple()` but recursive. 3228 3229 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. 3230 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3231 3232 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\: 3233 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3234 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3235 3236 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3237 `DMPlexGetDepth()`, `PetscSection`, `IS` 3238 @*/ 3239 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3240 { 3241 const PetscInt *arr0 = NULL, *cone = NULL; 3242 PetscInt *arr = NULL, *newarr = NULL; 3243 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3244 IS *expandedPoints_; 3245 PetscSection *sections_; 3246 3247 PetscFunctionBegin; 3248 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3249 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3250 if (depth) PetscAssertPointer(depth, 3); 3251 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3252 if (sections) PetscAssertPointer(sections, 5); 3253 PetscCall(ISGetLocalSize(points, &n)); 3254 PetscCall(ISGetIndices(points, &arr0)); 3255 PetscCall(DMPlexGetDepth(dm, &depth_)); 3256 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3257 PetscCall(PetscCalloc1(depth_, §ions_)); 3258 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3259 for (d = depth_ - 1; d >= 0; d--) { 3260 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3261 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3262 for (i = 0; i < n; i++) { 3263 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3264 if (arr[i] >= start && arr[i] < end) { 3265 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3266 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3267 } else { 3268 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3269 } 3270 } 3271 PetscCall(PetscSectionSetUp(sections_[d])); 3272 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3273 PetscCall(PetscMalloc1(newn, &newarr)); 3274 for (i = 0; i < n; i++) { 3275 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3276 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3277 if (cn > 1) { 3278 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3279 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3280 } else { 3281 newarr[co] = arr[i]; 3282 } 3283 } 3284 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3285 arr = newarr; 3286 n = newn; 3287 } 3288 PetscCall(ISRestoreIndices(points, &arr0)); 3289 *depth = depth_; 3290 if (expandedPoints) *expandedPoints = expandedPoints_; 3291 else { 3292 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3293 PetscCall(PetscFree(expandedPoints_)); 3294 } 3295 if (sections) *sections = sections_; 3296 else { 3297 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3298 PetscCall(PetscFree(sections_)); 3299 } 3300 PetscFunctionReturn(PETSC_SUCCESS); 3301 } 3302 3303 /*@ 3304 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3305 3306 Not Collective 3307 3308 Input Parameters: 3309 + dm - The `DMPLEX` 3310 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3311 3312 Output Parameters: 3313 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3314 . expandedPoints - (optional) An array of recursively expanded cones 3315 - sections - (optional) An array of sections which describe mappings from points to their cone points 3316 3317 Level: advanced 3318 3319 Note: 3320 See `DMPlexGetConeRecursive()` 3321 3322 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3323 `DMPlexGetDepth()`, `IS`, `PetscSection` 3324 @*/ 3325 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3326 { 3327 PetscInt d, depth_; 3328 3329 PetscFunctionBegin; 3330 PetscCall(DMPlexGetDepth(dm, &depth_)); 3331 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3332 if (depth) *depth = 0; 3333 if (expandedPoints) { 3334 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3335 PetscCall(PetscFree(*expandedPoints)); 3336 } 3337 if (sections) { 3338 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3339 PetscCall(PetscFree(*sections)); 3340 } 3341 PetscFunctionReturn(PETSC_SUCCESS); 3342 } 3343 3344 /*@ 3345 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 3346 3347 Not Collective 3348 3349 Input Parameters: 3350 + dm - The `DMPLEX` 3351 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3352 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3353 3354 Level: beginner 3355 3356 Note: 3357 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3358 3359 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3360 @*/ 3361 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3362 { 3363 DM_Plex *mesh = (DM_Plex *)dm->data; 3364 PetscInt dof, off, c; 3365 3366 PetscFunctionBegin; 3367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3368 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3369 if (dof) PetscAssertPointer(cone, 3); 3370 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3371 if (PetscDefined(USE_DEBUG)) { 3372 PetscInt pStart, pEnd; 3373 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3374 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); 3375 for (c = 0; c < dof; ++c) { 3376 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); 3377 mesh->cones[off + c] = cone[c]; 3378 } 3379 } else { 3380 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3381 } 3382 PetscFunctionReturn(PETSC_SUCCESS); 3383 } 3384 3385 /*@C 3386 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3387 3388 Not Collective 3389 3390 Input Parameters: 3391 + dm - The `DMPLEX` 3392 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3393 3394 Output Parameter: 3395 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3396 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3397 3398 Level: beginner 3399 3400 Note: 3401 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3402 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3403 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3404 with the identity. 3405 3406 Fortran Notes: 3407 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3408 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3409 3410 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3411 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3412 @*/ 3413 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3414 { 3415 DM_Plex *mesh = (DM_Plex *)dm->data; 3416 PetscInt off; 3417 3418 PetscFunctionBegin; 3419 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3420 if (PetscDefined(USE_DEBUG)) { 3421 PetscInt dof; 3422 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3423 if (dof) PetscAssertPointer(coneOrientation, 3); 3424 } 3425 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3426 3427 *coneOrientation = &mesh->coneOrientations[off]; 3428 PetscFunctionReturn(PETSC_SUCCESS); 3429 } 3430 3431 /*@ 3432 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3433 3434 Not Collective 3435 3436 Input Parameters: 3437 + dm - The `DMPLEX` 3438 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3439 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3440 3441 Level: beginner 3442 3443 Notes: 3444 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3445 3446 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3447 3448 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3449 @*/ 3450 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3451 { 3452 DM_Plex *mesh = (DM_Plex *)dm->data; 3453 PetscInt pStart, pEnd; 3454 PetscInt dof, off, c; 3455 3456 PetscFunctionBegin; 3457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3458 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3459 if (dof) PetscAssertPointer(coneOrientation, 3); 3460 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3461 if (PetscDefined(USE_DEBUG)) { 3462 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3463 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); 3464 for (c = 0; c < dof; ++c) { 3465 PetscInt cdof, o = coneOrientation[c]; 3466 3467 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3468 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); 3469 mesh->coneOrientations[off + c] = o; 3470 } 3471 } else { 3472 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3473 } 3474 PetscFunctionReturn(PETSC_SUCCESS); 3475 } 3476 3477 /*@ 3478 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3479 3480 Not Collective 3481 3482 Input Parameters: 3483 + dm - The `DMPLEX` 3484 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3485 . conePos - The local index in the cone where the point should be put 3486 - conePoint - The mesh point to insert 3487 3488 Level: beginner 3489 3490 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3491 @*/ 3492 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3493 { 3494 DM_Plex *mesh = (DM_Plex *)dm->data; 3495 PetscInt pStart, pEnd; 3496 PetscInt dof, off; 3497 3498 PetscFunctionBegin; 3499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3500 if (PetscDefined(USE_DEBUG)) { 3501 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3502 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); 3503 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); 3504 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3505 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); 3506 } 3507 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3508 mesh->cones[off + conePos] = conePoint; 3509 PetscFunctionReturn(PETSC_SUCCESS); 3510 } 3511 3512 /*@ 3513 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3514 3515 Not Collective 3516 3517 Input Parameters: 3518 + dm - The `DMPLEX` 3519 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3520 . conePos - The local index in the cone where the point should be put 3521 - coneOrientation - The point orientation to insert 3522 3523 Level: beginner 3524 3525 Note: 3526 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3527 3528 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3529 @*/ 3530 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3531 { 3532 DM_Plex *mesh = (DM_Plex *)dm->data; 3533 PetscInt pStart, pEnd; 3534 PetscInt dof, off; 3535 3536 PetscFunctionBegin; 3537 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3538 if (PetscDefined(USE_DEBUG)) { 3539 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3540 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); 3541 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3542 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); 3543 } 3544 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3545 mesh->coneOrientations[off + conePos] = coneOrientation; 3546 PetscFunctionReturn(PETSC_SUCCESS); 3547 } 3548 3549 /*@C 3550 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3551 3552 Not collective 3553 3554 Input Parameters: 3555 + dm - The DMPlex 3556 - p - The point, which must lie in the chart set with DMPlexSetChart() 3557 3558 Output Parameters: 3559 + cone - An array of points which are on the in-edges for point `p` 3560 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3561 integer giving the prescription for cone traversal. 3562 3563 Level: beginner 3564 3565 Notes: 3566 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3567 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3568 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3569 with the identity. 3570 3571 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3572 3573 Fortran Notes: 3574 `cone` and `ornt` must be declared with 3575 .vb 3576 PetscInt, pointer :: cone(:) 3577 PetscInt, pointer :: ornt(:) 3578 .ve 3579 3580 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3581 @*/ 3582 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3583 { 3584 DM_Plex *mesh = (DM_Plex *)dm->data; 3585 3586 PetscFunctionBegin; 3587 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3588 if (mesh->tr) { 3589 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3590 } else { 3591 PetscInt off; 3592 if (PetscDefined(USE_DEBUG)) { 3593 PetscInt dof; 3594 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3595 if (dof) { 3596 if (cone) PetscAssertPointer(cone, 3); 3597 if (ornt) PetscAssertPointer(ornt, 4); 3598 } 3599 } 3600 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3601 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3602 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3603 } 3604 PetscFunctionReturn(PETSC_SUCCESS); 3605 } 3606 3607 /*@C 3608 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3609 3610 Not Collective 3611 3612 Input Parameters: 3613 + dm - The DMPlex 3614 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3615 . cone - An array of points which are on the in-edges for point p 3616 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3617 integer giving the prescription for cone traversal. 3618 3619 Level: beginner 3620 3621 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3622 @*/ 3623 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3624 { 3625 DM_Plex *mesh = (DM_Plex *)dm->data; 3626 3627 PetscFunctionBegin; 3628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3629 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3630 PetscFunctionReturn(PETSC_SUCCESS); 3631 } 3632 3633 /*@ 3634 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3635 3636 Not Collective 3637 3638 Input Parameters: 3639 + dm - The `DMPLEX` 3640 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3641 3642 Output Parameter: 3643 . size - The support size for point `p` 3644 3645 Level: beginner 3646 3647 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3648 @*/ 3649 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3650 { 3651 DM_Plex *mesh = (DM_Plex *)dm->data; 3652 3653 PetscFunctionBegin; 3654 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3655 PetscAssertPointer(size, 3); 3656 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3657 PetscFunctionReturn(PETSC_SUCCESS); 3658 } 3659 3660 /*@ 3661 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3662 3663 Not Collective 3664 3665 Input Parameters: 3666 + dm - The `DMPLEX` 3667 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3668 - size - The support size for point `p` 3669 3670 Level: beginner 3671 3672 Note: 3673 This should be called after `DMPlexSetChart()`. 3674 3675 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3676 @*/ 3677 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3678 { 3679 DM_Plex *mesh = (DM_Plex *)dm->data; 3680 3681 PetscFunctionBegin; 3682 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3683 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3684 PetscFunctionReturn(PETSC_SUCCESS); 3685 } 3686 3687 /*@C 3688 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3689 3690 Not Collective 3691 3692 Input Parameters: 3693 + dm - The `DMPLEX` 3694 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3695 3696 Output Parameter: 3697 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3698 3699 Level: beginner 3700 3701 Fortran Notes: 3702 `support` must be declared with 3703 .vb 3704 PetscInt, pointer :: support(:) 3705 .ve 3706 3707 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3708 `DMPlexRestoreSupport()` is not needed/available in C. 3709 3710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3711 @*/ 3712 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3713 { 3714 DM_Plex *mesh = (DM_Plex *)dm->data; 3715 PetscInt off; 3716 3717 PetscFunctionBegin; 3718 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3719 PetscAssertPointer(support, 3); 3720 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3721 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3722 PetscFunctionReturn(PETSC_SUCCESS); 3723 } 3724 3725 /*@ 3726 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3727 3728 Not Collective 3729 3730 Input Parameters: 3731 + dm - The `DMPLEX` 3732 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3733 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3734 3735 Level: beginner 3736 3737 Note: 3738 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3739 3740 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3741 @*/ 3742 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3743 { 3744 DM_Plex *mesh = (DM_Plex *)dm->data; 3745 PetscInt pStart, pEnd; 3746 PetscInt dof, off, c; 3747 3748 PetscFunctionBegin; 3749 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3750 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3751 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3752 if (dof) PetscAssertPointer(support, 3); 3753 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3754 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); 3755 for (c = 0; c < dof; ++c) { 3756 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); 3757 mesh->supports[off + c] = support[c]; 3758 } 3759 PetscFunctionReturn(PETSC_SUCCESS); 3760 } 3761 3762 /*@ 3763 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3764 3765 Not Collective 3766 3767 Input Parameters: 3768 + dm - The `DMPLEX` 3769 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3770 . supportPos - The local index in the cone where the point should be put 3771 - supportPoint - The mesh point to insert 3772 3773 Level: beginner 3774 3775 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3776 @*/ 3777 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3778 { 3779 DM_Plex *mesh = (DM_Plex *)dm->data; 3780 PetscInt pStart, pEnd; 3781 PetscInt dof, off; 3782 3783 PetscFunctionBegin; 3784 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3785 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3786 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3787 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3788 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); 3789 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); 3790 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); 3791 mesh->supports[off + supportPos] = supportPoint; 3792 PetscFunctionReturn(PETSC_SUCCESS); 3793 } 3794 3795 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3796 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3797 { 3798 switch (ct) { 3799 case DM_POLYTOPE_SEGMENT: 3800 if (o == -1) return -2; 3801 break; 3802 case DM_POLYTOPE_TRIANGLE: 3803 if (o == -3) return -1; 3804 if (o == -2) return -3; 3805 if (o == -1) return -2; 3806 break; 3807 case DM_POLYTOPE_QUADRILATERAL: 3808 if (o == -4) return -2; 3809 if (o == -3) return -1; 3810 if (o == -2) return -4; 3811 if (o == -1) return -3; 3812 break; 3813 default: 3814 return o; 3815 } 3816 return o; 3817 } 3818 3819 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3820 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3821 { 3822 switch (ct) { 3823 case DM_POLYTOPE_SEGMENT: 3824 if ((o == -2) || (o == 1)) return -1; 3825 if (o == -1) return 0; 3826 break; 3827 case DM_POLYTOPE_TRIANGLE: 3828 if (o == -3) return -2; 3829 if (o == -2) return -1; 3830 if (o == -1) return -3; 3831 break; 3832 case DM_POLYTOPE_QUADRILATERAL: 3833 if (o == -4) return -2; 3834 if (o == -3) return -1; 3835 if (o == -2) return -4; 3836 if (o == -1) return -3; 3837 break; 3838 default: 3839 return o; 3840 } 3841 return o; 3842 } 3843 3844 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3845 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3846 { 3847 PetscInt pStart, pEnd, p; 3848 3849 PetscFunctionBegin; 3850 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3851 for (p = pStart; p < pEnd; ++p) { 3852 const PetscInt *cone, *ornt; 3853 PetscInt coneSize, c; 3854 3855 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3856 PetscCall(DMPlexGetCone(dm, p, &cone)); 3857 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3858 for (c = 0; c < coneSize; ++c) { 3859 DMPolytopeType ct; 3860 const PetscInt o = ornt[c]; 3861 3862 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3863 switch (ct) { 3864 case DM_POLYTOPE_SEGMENT: 3865 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3866 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3867 break; 3868 case DM_POLYTOPE_TRIANGLE: 3869 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3870 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3871 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3872 break; 3873 case DM_POLYTOPE_QUADRILATERAL: 3874 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3875 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3876 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3877 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3878 break; 3879 default: 3880 break; 3881 } 3882 } 3883 } 3884 PetscFunctionReturn(PETSC_SUCCESS); 3885 } 3886 3887 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3888 { 3889 DM_Plex *mesh = (DM_Plex *)dm->data; 3890 3891 PetscFunctionBeginHot; 3892 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3893 if (useCone) { 3894 PetscCall(DMPlexGetConeSize(dm, p, size)); 3895 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3896 } else { 3897 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3898 PetscCall(DMPlexGetSupport(dm, p, arr)); 3899 } 3900 } else { 3901 if (useCone) { 3902 const PetscSection s = mesh->coneSection; 3903 const PetscInt ps = p - s->pStart; 3904 const PetscInt off = s->atlasOff[ps]; 3905 3906 *size = s->atlasDof[ps]; 3907 *arr = mesh->cones + off; 3908 *ornt = mesh->coneOrientations + off; 3909 } else { 3910 const PetscSection s = mesh->supportSection; 3911 const PetscInt ps = p - s->pStart; 3912 const PetscInt off = s->atlasOff[ps]; 3913 3914 *size = s->atlasDof[ps]; 3915 *arr = mesh->supports + off; 3916 } 3917 } 3918 PetscFunctionReturn(PETSC_SUCCESS); 3919 } 3920 3921 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3922 { 3923 DM_Plex *mesh = (DM_Plex *)dm->data; 3924 3925 PetscFunctionBeginHot; 3926 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3927 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3928 } 3929 PetscFunctionReturn(PETSC_SUCCESS); 3930 } 3931 3932 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3933 { 3934 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3935 PetscInt *closure; 3936 const PetscInt *tmp = NULL, *tmpO = NULL; 3937 PetscInt off = 0, tmpSize, t; 3938 3939 PetscFunctionBeginHot; 3940 if (ornt) { 3941 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3942 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; 3943 } 3944 if (*points) { 3945 closure = *points; 3946 } else { 3947 PetscInt maxConeSize, maxSupportSize; 3948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3949 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3950 } 3951 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3952 if (ct == DM_POLYTOPE_UNKNOWN) { 3953 closure[off++] = p; 3954 closure[off++] = 0; 3955 for (t = 0; t < tmpSize; ++t) { 3956 closure[off++] = tmp[t]; 3957 closure[off++] = tmpO ? tmpO[t] : 0; 3958 } 3959 } else { 3960 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3961 3962 /* We assume that cells with a valid type have faces with a valid type */ 3963 closure[off++] = p; 3964 closure[off++] = ornt; 3965 for (t = 0; t < tmpSize; ++t) { 3966 DMPolytopeType ft; 3967 3968 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3969 closure[off++] = tmp[arr[t]]; 3970 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3971 } 3972 } 3973 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3974 if (numPoints) *numPoints = tmpSize + 1; 3975 if (points) *points = closure; 3976 PetscFunctionReturn(PETSC_SUCCESS); 3977 } 3978 3979 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3980 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3981 { 3982 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3983 const PetscInt *cone, *ornt; 3984 PetscInt *pts, *closure = NULL; 3985 DMPolytopeType ft; 3986 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3987 PetscInt dim, coneSize, c, d, clSize, cl; 3988 3989 PetscFunctionBeginHot; 3990 PetscCall(DMGetDimension(dm, &dim)); 3991 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3992 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3993 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3994 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3995 maxSize = PetscMax(coneSeries, supportSeries); 3996 if (*points) { 3997 pts = *points; 3998 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3999 c = 0; 4000 pts[c++] = point; 4001 pts[c++] = o; 4002 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4003 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4004 for (cl = 0; cl < clSize * 2; cl += 2) { 4005 pts[c++] = closure[cl]; 4006 pts[c++] = closure[cl + 1]; 4007 } 4008 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4009 for (cl = 0; cl < clSize * 2; cl += 2) { 4010 pts[c++] = closure[cl]; 4011 pts[c++] = closure[cl + 1]; 4012 } 4013 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4014 for (d = 2; d < coneSize; ++d) { 4015 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4016 pts[c++] = cone[arr[d * 2 + 0]]; 4017 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4018 } 4019 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4020 if (dim >= 3) { 4021 for (d = 2; d < coneSize; ++d) { 4022 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4023 const PetscInt *fcone, *fornt; 4024 PetscInt fconeSize, fc, i; 4025 4026 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4027 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4028 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4029 for (fc = 0; fc < fconeSize; ++fc) { 4030 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4031 const PetscInt co = farr[fc * 2 + 1]; 4032 4033 for (i = 0; i < c; i += 2) 4034 if (pts[i] == cp) break; 4035 if (i == c) { 4036 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4037 pts[c++] = cp; 4038 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4039 } 4040 } 4041 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4042 } 4043 } 4044 *numPoints = c / 2; 4045 *points = pts; 4046 PetscFunctionReturn(PETSC_SUCCESS); 4047 } 4048 4049 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4050 { 4051 DMPolytopeType ct; 4052 PetscInt *closure, *fifo; 4053 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4054 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4055 PetscInt depth, maxSize; 4056 4057 PetscFunctionBeginHot; 4058 PetscCall(DMPlexGetDepth(dm, &depth)); 4059 if (depth == 1) { 4060 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4061 PetscFunctionReturn(PETSC_SUCCESS); 4062 } 4063 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4064 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; 4065 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4066 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4067 PetscFunctionReturn(PETSC_SUCCESS); 4068 } 4069 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4070 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4071 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4072 maxSize = PetscMax(coneSeries, supportSeries); 4073 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4074 if (*points) { 4075 closure = *points; 4076 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4077 closure[closureSize++] = p; 4078 closure[closureSize++] = ornt; 4079 fifo[fifoSize++] = p; 4080 fifo[fifoSize++] = ornt; 4081 fifo[fifoSize++] = ct; 4082 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4083 while (fifoSize - fifoStart) { 4084 const PetscInt q = fifo[fifoStart++]; 4085 const PetscInt o = fifo[fifoStart++]; 4086 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4087 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4088 const PetscInt *tmp, *tmpO = NULL; 4089 PetscInt tmpSize, t; 4090 4091 if (PetscDefined(USE_DEBUG)) { 4092 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4093 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); 4094 } 4095 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4096 for (t = 0; t < tmpSize; ++t) { 4097 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4098 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4099 const PetscInt cp = tmp[ip]; 4100 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4101 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4102 PetscInt c; 4103 4104 /* Check for duplicate */ 4105 for (c = 0; c < closureSize; c += 2) { 4106 if (closure[c] == cp) break; 4107 } 4108 if (c == closureSize) { 4109 closure[closureSize++] = cp; 4110 closure[closureSize++] = co; 4111 fifo[fifoSize++] = cp; 4112 fifo[fifoSize++] = co; 4113 fifo[fifoSize++] = ct; 4114 } 4115 } 4116 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4117 } 4118 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4119 if (numPoints) *numPoints = closureSize / 2; 4120 if (points) *points = closure; 4121 PetscFunctionReturn(PETSC_SUCCESS); 4122 } 4123 4124 /*@C 4125 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4126 4127 Not Collective 4128 4129 Input Parameters: 4130 + dm - The `DMPLEX` 4131 . p - The mesh point 4132 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4133 4134 Input/Output Parameter: 4135 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4136 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4137 otherwise the provided array is used to hold the values 4138 4139 Output Parameter: 4140 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4141 4142 Level: beginner 4143 4144 Note: 4145 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4146 4147 Fortran Notes: 4148 `points` must be declared with 4149 .vb 4150 PetscInt, pointer :: points(:) 4151 .ve 4152 and is always allocated by the function. 4153 4154 The `numPoints` argument is not present in the Fortran binding. 4155 4156 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4157 @*/ 4158 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4159 { 4160 PetscFunctionBeginHot; 4161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4162 if (numPoints) PetscAssertPointer(numPoints, 4); 4163 if (points) PetscAssertPointer(points, 5); 4164 if (PetscDefined(USE_DEBUG)) { 4165 PetscInt pStart, pEnd; 4166 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4167 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); 4168 } 4169 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4170 PetscFunctionReturn(PETSC_SUCCESS); 4171 } 4172 4173 /*@C 4174 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4175 4176 Not Collective 4177 4178 Input Parameters: 4179 + dm - The `DMPLEX` 4180 . p - The mesh point 4181 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4182 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4183 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4184 4185 Level: beginner 4186 4187 Note: 4188 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4189 4190 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4191 @*/ 4192 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4193 { 4194 PetscFunctionBeginHot; 4195 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4196 if (numPoints) *numPoints = 0; 4197 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4198 PetscFunctionReturn(PETSC_SUCCESS); 4199 } 4200 4201 /*@ 4202 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4203 4204 Not Collective 4205 4206 Input Parameter: 4207 . dm - The `DMPLEX` 4208 4209 Output Parameters: 4210 + maxConeSize - The maximum number of in-edges 4211 - maxSupportSize - The maximum number of out-edges 4212 4213 Level: beginner 4214 4215 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4216 @*/ 4217 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4218 { 4219 DM_Plex *mesh = (DM_Plex *)dm->data; 4220 4221 PetscFunctionBegin; 4222 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4223 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4224 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4225 PetscFunctionReturn(PETSC_SUCCESS); 4226 } 4227 4228 PetscErrorCode DMSetUp_Plex(DM dm) 4229 { 4230 DM_Plex *mesh = (DM_Plex *)dm->data; 4231 PetscInt size, maxSupportSize; 4232 4233 PetscFunctionBegin; 4234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4235 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4236 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4237 PetscCall(PetscMalloc1(size, &mesh->cones)); 4238 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4239 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4240 if (maxSupportSize) { 4241 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4242 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4243 PetscCall(PetscMalloc1(size, &mesh->supports)); 4244 } 4245 PetscFunctionReturn(PETSC_SUCCESS); 4246 } 4247 4248 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4249 { 4250 PetscFunctionBegin; 4251 if (subdm) PetscCall(DMClone(dm, subdm)); 4252 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4253 if (subdm) (*subdm)->useNatural = dm->useNatural; 4254 if (dm->useNatural && dm->sfMigration) { 4255 PetscSF sfNatural; 4256 4257 (*subdm)->sfMigration = dm->sfMigration; 4258 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4259 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4260 (*subdm)->sfNatural = sfNatural; 4261 } 4262 PetscFunctionReturn(PETSC_SUCCESS); 4263 } 4264 4265 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4266 { 4267 PetscInt i = 0; 4268 4269 PetscFunctionBegin; 4270 PetscCall(DMClone(dms[0], superdm)); 4271 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4272 (*superdm)->useNatural = PETSC_FALSE; 4273 for (i = 0; i < len; i++) { 4274 if (dms[i]->useNatural && dms[i]->sfMigration) { 4275 PetscSF sfNatural; 4276 4277 (*superdm)->sfMigration = dms[i]->sfMigration; 4278 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4279 (*superdm)->useNatural = PETSC_TRUE; 4280 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4281 (*superdm)->sfNatural = sfNatural; 4282 break; 4283 } 4284 } 4285 PetscFunctionReturn(PETSC_SUCCESS); 4286 } 4287 4288 /*@ 4289 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4290 4291 Not Collective 4292 4293 Input Parameter: 4294 . dm - The `DMPLEX` 4295 4296 Level: beginner 4297 4298 Note: 4299 This should be called after all calls to `DMPlexSetCone()` 4300 4301 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4302 @*/ 4303 PetscErrorCode DMPlexSymmetrize(DM dm) 4304 { 4305 DM_Plex *mesh = (DM_Plex *)dm->data; 4306 PetscInt *offsets; 4307 PetscInt supportSize; 4308 PetscInt pStart, pEnd, p; 4309 4310 PetscFunctionBegin; 4311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4312 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4313 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4314 /* Calculate support sizes */ 4315 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4316 for (p = pStart; p < pEnd; ++p) { 4317 PetscInt dof, off, c; 4318 4319 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4320 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4321 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4322 } 4323 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4324 /* Calculate supports */ 4325 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4326 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4327 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4328 for (p = pStart; p < pEnd; ++p) { 4329 PetscInt dof, off, c; 4330 4331 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4332 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4333 for (c = off; c < off + dof; ++c) { 4334 const PetscInt q = mesh->cones[c]; 4335 PetscInt offS; 4336 4337 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4338 4339 mesh->supports[offS + offsets[q]] = p; 4340 ++offsets[q]; 4341 } 4342 } 4343 PetscCall(PetscFree(offsets)); 4344 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4345 PetscFunctionReturn(PETSC_SUCCESS); 4346 } 4347 4348 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4349 { 4350 IS stratumIS; 4351 4352 PetscFunctionBegin; 4353 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4354 if (PetscDefined(USE_DEBUG)) { 4355 PetscInt qStart, qEnd, numLevels, level; 4356 PetscBool overlap = PETSC_FALSE; 4357 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4358 for (level = 0; level < numLevels; level++) { 4359 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4360 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4361 overlap = PETSC_TRUE; 4362 break; 4363 } 4364 } 4365 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); 4366 } 4367 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4368 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4369 PetscCall(ISDestroy(&stratumIS)); 4370 PetscFunctionReturn(PETSC_SUCCESS); 4371 } 4372 4373 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4374 { 4375 PetscInt *pMin, *pMax; 4376 PetscInt pStart, pEnd; 4377 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4378 4379 PetscFunctionBegin; 4380 { 4381 DMLabel label2; 4382 4383 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4384 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4385 } 4386 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4387 for (PetscInt p = pStart; p < pEnd; ++p) { 4388 DMPolytopeType ct; 4389 4390 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4391 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4392 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4393 } 4394 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4395 for (PetscInt d = dmin; d <= dmax; ++d) { 4396 pMin[d] = PETSC_INT_MAX; 4397 pMax[d] = PETSC_INT_MIN; 4398 } 4399 for (PetscInt p = pStart; p < pEnd; ++p) { 4400 DMPolytopeType ct; 4401 PetscInt d; 4402 4403 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4404 d = DMPolytopeTypeGetDim(ct); 4405 pMin[d] = PetscMin(p, pMin[d]); 4406 pMax[d] = PetscMax(p, pMax[d]); 4407 } 4408 for (PetscInt d = dmin; d <= dmax; ++d) { 4409 if (pMin[d] > pMax[d]) continue; 4410 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4411 } 4412 PetscCall(PetscFree2(pMin, pMax)); 4413 PetscFunctionReturn(PETSC_SUCCESS); 4414 } 4415 4416 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4417 { 4418 PetscInt pStart, pEnd; 4419 PetscInt numRoots = 0, numLeaves = 0; 4420 4421 PetscFunctionBegin; 4422 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4423 { 4424 /* Initialize roots and count leaves */ 4425 PetscInt sMin = PETSC_INT_MAX; 4426 PetscInt sMax = PETSC_INT_MIN; 4427 PetscInt coneSize, supportSize; 4428 4429 for (PetscInt p = pStart; p < pEnd; ++p) { 4430 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4431 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4432 if (!coneSize && supportSize) { 4433 sMin = PetscMin(p, sMin); 4434 sMax = PetscMax(p, sMax); 4435 ++numRoots; 4436 } else if (!supportSize && coneSize) { 4437 ++numLeaves; 4438 } else if (!supportSize && !coneSize) { 4439 /* Isolated points */ 4440 sMin = PetscMin(p, sMin); 4441 sMax = PetscMax(p, sMax); 4442 } 4443 } 4444 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4445 } 4446 4447 if (numRoots + numLeaves == (pEnd - pStart)) { 4448 PetscInt sMin = PETSC_INT_MAX; 4449 PetscInt sMax = PETSC_INT_MIN; 4450 PetscInt coneSize, supportSize; 4451 4452 for (PetscInt p = pStart; p < pEnd; ++p) { 4453 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4454 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4455 if (!supportSize && coneSize) { 4456 sMin = PetscMin(p, sMin); 4457 sMax = PetscMax(p, sMax); 4458 } 4459 } 4460 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4461 } else { 4462 PetscInt level = 0; 4463 PetscInt qStart, qEnd; 4464 4465 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4466 while (qEnd > qStart) { 4467 PetscInt sMin = PETSC_INT_MAX; 4468 PetscInt sMax = PETSC_INT_MIN; 4469 4470 for (PetscInt q = qStart; q < qEnd; ++q) { 4471 const PetscInt *support; 4472 PetscInt supportSize; 4473 4474 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4475 PetscCall(DMPlexGetSupport(dm, q, &support)); 4476 for (PetscInt s = 0; s < supportSize; ++s) { 4477 sMin = PetscMin(support[s], sMin); 4478 sMax = PetscMax(support[s], sMax); 4479 } 4480 } 4481 PetscCall(DMLabelGetNumValues(label, &level)); 4482 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4483 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4484 } 4485 } 4486 PetscFunctionReturn(PETSC_SUCCESS); 4487 } 4488 4489 /*@ 4490 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4491 4492 Collective 4493 4494 Input Parameter: 4495 . dm - The `DMPLEX` 4496 4497 Level: beginner 4498 4499 Notes: 4500 The strata group all points of the same grade, and this function calculates the strata. This 4501 grade can be seen as the height (or depth) of the point in the DAG. 4502 4503 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4504 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4505 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4506 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4507 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4508 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4509 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4510 4511 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4512 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4513 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 4514 to interpolate only that one (e0), so that 4515 .vb 4516 cone(c0) = {e0, v2} 4517 cone(e0) = {v0, v1} 4518 .ve 4519 If `DMPlexStratify()` is run on this mesh, it will give depths 4520 .vb 4521 depth 0 = {v0, v1, v2} 4522 depth 1 = {e0, c0} 4523 .ve 4524 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4525 4526 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4527 4528 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4529 @*/ 4530 PetscErrorCode DMPlexStratify(DM dm) 4531 { 4532 DM_Plex *mesh = (DM_Plex *)dm->data; 4533 DMLabel label; 4534 PetscBool flg = PETSC_FALSE; 4535 4536 PetscFunctionBegin; 4537 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4538 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4539 4540 // Create depth label 4541 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4542 PetscCall(DMCreateLabel(dm, "depth")); 4543 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4544 4545 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4546 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4547 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4548 4549 { /* just in case there is an empty process */ 4550 PetscInt numValues, maxValues = 0, v; 4551 4552 PetscCall(DMLabelGetNumValues(label, &numValues)); 4553 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4554 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4555 } 4556 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4557 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4558 PetscFunctionReturn(PETSC_SUCCESS); 4559 } 4560 4561 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4562 { 4563 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4564 PetscInt dim, depth, pheight, coneSize; 4565 4566 PetscFunctionBeginHot; 4567 PetscCall(DMGetDimension(dm, &dim)); 4568 PetscCall(DMPlexGetDepth(dm, &depth)); 4569 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4570 pheight = depth - pdepth; 4571 if (depth <= 1) { 4572 switch (pdepth) { 4573 case 0: 4574 ct = DM_POLYTOPE_POINT; 4575 break; 4576 case 1: 4577 switch (coneSize) { 4578 case 2: 4579 ct = DM_POLYTOPE_SEGMENT; 4580 break; 4581 case 3: 4582 ct = DM_POLYTOPE_TRIANGLE; 4583 break; 4584 case 4: 4585 switch (dim) { 4586 case 2: 4587 ct = DM_POLYTOPE_QUADRILATERAL; 4588 break; 4589 case 3: 4590 ct = DM_POLYTOPE_TETRAHEDRON; 4591 break; 4592 default: 4593 break; 4594 } 4595 break; 4596 case 5: 4597 ct = DM_POLYTOPE_PYRAMID; 4598 break; 4599 case 6: 4600 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4601 break; 4602 case 8: 4603 ct = DM_POLYTOPE_HEXAHEDRON; 4604 break; 4605 default: 4606 break; 4607 } 4608 } 4609 } else { 4610 if (pdepth == 0) { 4611 ct = DM_POLYTOPE_POINT; 4612 } else if (pheight == 0) { 4613 switch (dim) { 4614 case 1: 4615 switch (coneSize) { 4616 case 2: 4617 ct = DM_POLYTOPE_SEGMENT; 4618 break; 4619 default: 4620 break; 4621 } 4622 break; 4623 case 2: 4624 switch (coneSize) { 4625 case 3: 4626 ct = DM_POLYTOPE_TRIANGLE; 4627 break; 4628 case 4: 4629 ct = DM_POLYTOPE_QUADRILATERAL; 4630 break; 4631 default: 4632 break; 4633 } 4634 break; 4635 case 3: 4636 switch (coneSize) { 4637 case 4: 4638 ct = DM_POLYTOPE_TETRAHEDRON; 4639 break; 4640 case 5: { 4641 const PetscInt *cone; 4642 PetscInt faceConeSize; 4643 4644 PetscCall(DMPlexGetCone(dm, p, &cone)); 4645 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4646 switch (faceConeSize) { 4647 case 3: 4648 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4649 break; 4650 case 4: 4651 ct = DM_POLYTOPE_PYRAMID; 4652 break; 4653 } 4654 } break; 4655 case 6: 4656 ct = DM_POLYTOPE_HEXAHEDRON; 4657 break; 4658 default: 4659 break; 4660 } 4661 break; 4662 default: 4663 break; 4664 } 4665 } else if (pheight > 0) { 4666 switch (coneSize) { 4667 case 2: 4668 ct = DM_POLYTOPE_SEGMENT; 4669 break; 4670 case 3: 4671 ct = DM_POLYTOPE_TRIANGLE; 4672 break; 4673 case 4: 4674 ct = DM_POLYTOPE_QUADRILATERAL; 4675 break; 4676 default: 4677 break; 4678 } 4679 } 4680 } 4681 *pt = ct; 4682 PetscFunctionReturn(PETSC_SUCCESS); 4683 } 4684 4685 /*@ 4686 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4687 4688 Collective 4689 4690 Input Parameter: 4691 . dm - The `DMPLEX` 4692 4693 Level: developer 4694 4695 Note: 4696 This function is normally called automatically when a cell type is requested. It creates an 4697 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4698 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4699 4700 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4701 4702 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4703 @*/ 4704 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4705 { 4706 DM_Plex *mesh; 4707 DMLabel ctLabel; 4708 PetscInt pStart, pEnd, p; 4709 4710 PetscFunctionBegin; 4711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4712 mesh = (DM_Plex *)dm->data; 4713 PetscCall(DMCreateLabel(dm, "celltype")); 4714 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4715 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4716 PetscCall(PetscFree(mesh->cellTypes)); 4717 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4718 for (p = pStart; p < pEnd; ++p) { 4719 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4720 PetscInt pdepth; 4721 4722 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4723 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4724 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]); 4725 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4726 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4727 } 4728 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4729 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4730 PetscFunctionReturn(PETSC_SUCCESS); 4731 } 4732 4733 /*@C 4734 DMPlexGetJoin - Get an array for the join of the set of points 4735 4736 Not Collective 4737 4738 Input Parameters: 4739 + dm - The `DMPLEX` object 4740 . numPoints - The number of input points for the join 4741 - points - The input points 4742 4743 Output Parameters: 4744 + numCoveredPoints - The number of points in the join 4745 - coveredPoints - The points in the join 4746 4747 Level: intermediate 4748 4749 Note: 4750 Currently, this is restricted to a single level join 4751 4752 Fortran Notes: 4753 `converedPoints` must be declared with 4754 .vb 4755 PetscInt, pointer :: coveredPints(:) 4756 .ve 4757 4758 The `numCoveredPoints` argument is not present in the Fortran binding. 4759 4760 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4761 @*/ 4762 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4763 { 4764 DM_Plex *mesh = (DM_Plex *)dm->data; 4765 PetscInt *join[2]; 4766 PetscInt joinSize, i = 0; 4767 PetscInt dof, off, p, c, m; 4768 PetscInt maxSupportSize; 4769 4770 PetscFunctionBegin; 4771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4772 PetscAssertPointer(points, 3); 4773 PetscAssertPointer(numCoveredPoints, 4); 4774 PetscAssertPointer(coveredPoints, 5); 4775 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4776 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4777 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4778 /* Copy in support of first point */ 4779 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4780 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4781 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4782 /* Check each successive support */ 4783 for (p = 1; p < numPoints; ++p) { 4784 PetscInt newJoinSize = 0; 4785 4786 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4787 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4788 for (c = 0; c < dof; ++c) { 4789 const PetscInt point = mesh->supports[off + c]; 4790 4791 for (m = 0; m < joinSize; ++m) { 4792 if (point == join[i][m]) { 4793 join[1 - i][newJoinSize++] = point; 4794 break; 4795 } 4796 } 4797 } 4798 joinSize = newJoinSize; 4799 i = 1 - i; 4800 } 4801 *numCoveredPoints = joinSize; 4802 *coveredPoints = join[i]; 4803 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4804 PetscFunctionReturn(PETSC_SUCCESS); 4805 } 4806 4807 /*@C 4808 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4809 4810 Not Collective 4811 4812 Input Parameters: 4813 + dm - The `DMPLEX` object 4814 . numPoints - The number of input points for the join 4815 - points - The input points 4816 4817 Output Parameters: 4818 + numCoveredPoints - The number of points in the join 4819 - coveredPoints - The points in the join 4820 4821 Level: intermediate 4822 4823 Fortran Notes: 4824 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4825 4826 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4827 @*/ 4828 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4829 { 4830 PetscFunctionBegin; 4831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4832 if (points) PetscAssertPointer(points, 3); 4833 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4834 PetscAssertPointer(coveredPoints, 5); 4835 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4836 if (numCoveredPoints) *numCoveredPoints = 0; 4837 PetscFunctionReturn(PETSC_SUCCESS); 4838 } 4839 4840 /*@C 4841 DMPlexGetFullJoin - Get an array for the join of the set of points 4842 4843 Not Collective 4844 4845 Input Parameters: 4846 + dm - The `DMPLEX` object 4847 . numPoints - The number of input points for the join 4848 - points - The input points, its length is `numPoints` 4849 4850 Output Parameters: 4851 + numCoveredPoints - The number of points in the join 4852 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4853 4854 Level: intermediate 4855 4856 Fortran Notes: 4857 `points` and `converedPoints` must be declared with 4858 .vb 4859 PetscInt, pointer :: points(:) 4860 PetscInt, pointer :: coveredPints(:) 4861 .ve 4862 4863 The `numCoveredPoints` argument is not present in the Fortran binding. 4864 4865 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4866 @*/ 4867 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4868 { 4869 PetscInt *offsets, **closures; 4870 PetscInt *join[2]; 4871 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4872 PetscInt p, d, c, m, ms; 4873 4874 PetscFunctionBegin; 4875 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4876 PetscAssertPointer(points, 3); 4877 PetscAssertPointer(numCoveredPoints, 4); 4878 PetscAssertPointer(coveredPoints, 5); 4879 4880 PetscCall(DMPlexGetDepth(dm, &depth)); 4881 PetscCall(PetscCalloc1(numPoints, &closures)); 4882 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4883 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4884 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4885 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4886 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4887 4888 for (p = 0; p < numPoints; ++p) { 4889 PetscInt closureSize; 4890 4891 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4892 4893 offsets[p * (depth + 2) + 0] = 0; 4894 for (d = 0; d < depth + 1; ++d) { 4895 PetscInt pStart, pEnd, i; 4896 4897 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4898 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4899 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4900 offsets[p * (depth + 2) + d + 1] = i; 4901 break; 4902 } 4903 } 4904 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4905 } 4906 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); 4907 } 4908 for (d = 0; d < depth + 1; ++d) { 4909 PetscInt dof; 4910 4911 /* Copy in support of first point */ 4912 dof = offsets[d + 1] - offsets[d]; 4913 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4914 /* Check each successive cone */ 4915 for (p = 1; p < numPoints && joinSize; ++p) { 4916 PetscInt newJoinSize = 0; 4917 4918 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4919 for (c = 0; c < dof; ++c) { 4920 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4921 4922 for (m = 0; m < joinSize; ++m) { 4923 if (point == join[i][m]) { 4924 join[1 - i][newJoinSize++] = point; 4925 break; 4926 } 4927 } 4928 } 4929 joinSize = newJoinSize; 4930 i = 1 - i; 4931 } 4932 if (joinSize) break; 4933 } 4934 *numCoveredPoints = joinSize; 4935 *coveredPoints = join[i]; 4936 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4937 PetscCall(PetscFree(closures)); 4938 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4939 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4940 PetscFunctionReturn(PETSC_SUCCESS); 4941 } 4942 4943 /*@C 4944 DMPlexGetMeet - Get an array for the meet of the set of points 4945 4946 Not Collective 4947 4948 Input Parameters: 4949 + dm - The `DMPLEX` object 4950 . numPoints - The number of input points for the meet 4951 - points - The input points, of length `numPoints` 4952 4953 Output Parameters: 4954 + numCoveringPoints - The number of points in the meet 4955 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4956 4957 Level: intermediate 4958 4959 Note: 4960 Currently, this is restricted to a single level meet 4961 4962 Fortran Notes: 4963 `coveringPoints` must be declared with 4964 .vb 4965 PetscInt, pointer :: coveringPoints(:) 4966 .ve 4967 4968 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4969 4970 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4971 @*/ 4972 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4973 { 4974 DM_Plex *mesh = (DM_Plex *)dm->data; 4975 PetscInt *meet[2]; 4976 PetscInt meetSize, i = 0; 4977 PetscInt dof, off, p, c, m; 4978 PetscInt maxConeSize; 4979 4980 PetscFunctionBegin; 4981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4982 PetscAssertPointer(points, 3); 4983 PetscAssertPointer(numCoveringPoints, 4); 4984 PetscAssertPointer(coveringPoints, 5); 4985 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4986 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4987 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4988 /* Copy in cone of first point */ 4989 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4990 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4991 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4992 /* Check each successive cone */ 4993 for (p = 1; p < numPoints; ++p) { 4994 PetscInt newMeetSize = 0; 4995 4996 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4997 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4998 for (c = 0; c < dof; ++c) { 4999 const PetscInt point = mesh->cones[off + c]; 5000 5001 for (m = 0; m < meetSize; ++m) { 5002 if (point == meet[i][m]) { 5003 meet[1 - i][newMeetSize++] = point; 5004 break; 5005 } 5006 } 5007 } 5008 meetSize = newMeetSize; 5009 i = 1 - i; 5010 } 5011 *numCoveringPoints = meetSize; 5012 *coveringPoints = meet[i]; 5013 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5014 PetscFunctionReturn(PETSC_SUCCESS); 5015 } 5016 5017 /*@C 5018 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5019 5020 Not Collective 5021 5022 Input Parameters: 5023 + dm - The `DMPLEX` object 5024 . numPoints - The number of input points for the meet 5025 - points - The input points 5026 5027 Output Parameters: 5028 + numCoveredPoints - The number of points in the meet 5029 - coveredPoints - The points in the meet 5030 5031 Level: intermediate 5032 5033 Fortran Notes: 5034 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5035 5036 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5037 @*/ 5038 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5039 { 5040 PetscFunctionBegin; 5041 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5042 if (points) PetscAssertPointer(points, 3); 5043 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5044 PetscAssertPointer(coveredPoints, 5); 5045 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5046 if (numCoveredPoints) *numCoveredPoints = 0; 5047 PetscFunctionReturn(PETSC_SUCCESS); 5048 } 5049 5050 /*@C 5051 DMPlexGetFullMeet - Get an array for the meet of the set of points 5052 5053 Not Collective 5054 5055 Input Parameters: 5056 + dm - The `DMPLEX` object 5057 . numPoints - The number of input points for the meet 5058 - points - The input points, of length `numPoints` 5059 5060 Output Parameters: 5061 + numCoveredPoints - The number of points in the meet 5062 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5063 5064 Level: intermediate 5065 5066 Fortran Notes: 5067 `points` and `coveredPoints` must be declared with 5068 .vb 5069 PetscInt, pointer :: points(:) 5070 PetscInt, pointer :: coveredPoints(:) 5071 .ve 5072 5073 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5074 5075 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5076 @*/ 5077 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5078 { 5079 PetscInt *offsets, **closures; 5080 PetscInt *meet[2]; 5081 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5082 PetscInt p, h, c, m, mc; 5083 5084 PetscFunctionBegin; 5085 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5086 PetscAssertPointer(points, 3); 5087 PetscAssertPointer(numCoveredPoints, 4); 5088 PetscAssertPointer(coveredPoints, 5); 5089 5090 PetscCall(DMPlexGetDepth(dm, &height)); 5091 PetscCall(PetscMalloc1(numPoints, &closures)); 5092 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5093 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5094 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5095 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5096 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5097 5098 for (p = 0; p < numPoints; ++p) { 5099 PetscInt closureSize; 5100 5101 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5102 5103 offsets[p * (height + 2) + 0] = 0; 5104 for (h = 0; h < height + 1; ++h) { 5105 PetscInt pStart, pEnd, i; 5106 5107 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5108 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5109 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5110 offsets[p * (height + 2) + h + 1] = i; 5111 break; 5112 } 5113 } 5114 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5115 } 5116 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); 5117 } 5118 for (h = 0; h < height + 1; ++h) { 5119 PetscInt dof; 5120 5121 /* Copy in cone of first point */ 5122 dof = offsets[h + 1] - offsets[h]; 5123 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5124 /* Check each successive cone */ 5125 for (p = 1; p < numPoints && meetSize; ++p) { 5126 PetscInt newMeetSize = 0; 5127 5128 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5129 for (c = 0; c < dof; ++c) { 5130 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5131 5132 for (m = 0; m < meetSize; ++m) { 5133 if (point == meet[i][m]) { 5134 meet[1 - i][newMeetSize++] = point; 5135 break; 5136 } 5137 } 5138 } 5139 meetSize = newMeetSize; 5140 i = 1 - i; 5141 } 5142 if (meetSize) break; 5143 } 5144 *numCoveredPoints = meetSize; 5145 *coveredPoints = meet[i]; 5146 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5147 PetscCall(PetscFree(closures)); 5148 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5149 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5150 PetscFunctionReturn(PETSC_SUCCESS); 5151 } 5152 5153 /*@ 5154 DMPlexEqual - Determine if two `DM` have the same topology 5155 5156 Not Collective 5157 5158 Input Parameters: 5159 + dmA - A `DMPLEX` object 5160 - dmB - A `DMPLEX` object 5161 5162 Output Parameter: 5163 . equal - `PETSC_TRUE` if the topologies are identical 5164 5165 Level: intermediate 5166 5167 Note: 5168 We are not solving graph isomorphism, so we do not permute. 5169 5170 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5171 @*/ 5172 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5173 { 5174 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5175 5176 PetscFunctionBegin; 5177 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5178 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5179 PetscAssertPointer(equal, 3); 5180 5181 *equal = PETSC_FALSE; 5182 PetscCall(DMPlexGetDepth(dmA, &depth)); 5183 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5184 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5185 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5186 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5187 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5188 for (p = pStart; p < pEnd; ++p) { 5189 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5190 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5191 5192 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5193 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5194 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5195 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5196 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5197 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5198 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5199 for (c = 0; c < coneSize; ++c) { 5200 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5201 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5202 } 5203 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5204 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5205 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5206 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5207 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5208 for (s = 0; s < supportSize; ++s) { 5209 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5210 } 5211 } 5212 *equal = PETSC_TRUE; 5213 PetscFunctionReturn(PETSC_SUCCESS); 5214 } 5215 5216 /*@ 5217 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5218 5219 Not Collective 5220 5221 Input Parameters: 5222 + dm - The `DMPLEX` 5223 . cellDim - The cell dimension 5224 - numCorners - The number of vertices on a cell 5225 5226 Output Parameter: 5227 . numFaceVertices - The number of vertices on a face 5228 5229 Level: developer 5230 5231 Note: 5232 Of course this can only work for a restricted set of symmetric shapes 5233 5234 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5235 @*/ 5236 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5237 { 5238 MPI_Comm comm; 5239 5240 PetscFunctionBegin; 5241 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5242 PetscAssertPointer(numFaceVertices, 4); 5243 switch (cellDim) { 5244 case 0: 5245 *numFaceVertices = 0; 5246 break; 5247 case 1: 5248 *numFaceVertices = 1; 5249 break; 5250 case 2: 5251 switch (numCorners) { 5252 case 3: /* triangle */ 5253 *numFaceVertices = 2; /* Edge has 2 vertices */ 5254 break; 5255 case 4: /* quadrilateral */ 5256 *numFaceVertices = 2; /* Edge has 2 vertices */ 5257 break; 5258 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5259 *numFaceVertices = 3; /* Edge has 3 vertices */ 5260 break; 5261 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5262 *numFaceVertices = 3; /* Edge has 3 vertices */ 5263 break; 5264 default: 5265 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5266 } 5267 break; 5268 case 3: 5269 switch (numCorners) { 5270 case 4: /* tetradehdron */ 5271 *numFaceVertices = 3; /* Face has 3 vertices */ 5272 break; 5273 case 6: /* tet cohesive cells */ 5274 *numFaceVertices = 4; /* Face has 4 vertices */ 5275 break; 5276 case 8: /* hexahedron */ 5277 *numFaceVertices = 4; /* Face has 4 vertices */ 5278 break; 5279 case 9: /* tet cohesive Lagrange cells */ 5280 *numFaceVertices = 6; /* Face has 6 vertices */ 5281 break; 5282 case 10: /* quadratic tetrahedron */ 5283 *numFaceVertices = 6; /* Face has 6 vertices */ 5284 break; 5285 case 12: /* hex cohesive Lagrange cells */ 5286 *numFaceVertices = 6; /* Face has 6 vertices */ 5287 break; 5288 case 18: /* quadratic tet cohesive Lagrange cells */ 5289 *numFaceVertices = 6; /* Face has 6 vertices */ 5290 break; 5291 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5292 *numFaceVertices = 9; /* Face has 9 vertices */ 5293 break; 5294 default: 5295 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5296 } 5297 break; 5298 default: 5299 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5300 } 5301 PetscFunctionReturn(PETSC_SUCCESS); 5302 } 5303 5304 /*@ 5305 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5306 5307 Not Collective 5308 5309 Input Parameter: 5310 . dm - The `DMPLEX` object 5311 5312 Output Parameter: 5313 . depthLabel - The `DMLabel` recording point depth 5314 5315 Level: developer 5316 5317 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5318 @*/ 5319 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5320 { 5321 PetscFunctionBegin; 5322 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5323 PetscAssertPointer(depthLabel, 2); 5324 *depthLabel = dm->depthLabel; 5325 PetscFunctionReturn(PETSC_SUCCESS); 5326 } 5327 5328 /*@ 5329 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5330 5331 Not Collective 5332 5333 Input Parameter: 5334 . dm - The `DMPLEX` object 5335 5336 Output Parameter: 5337 . depth - The number of strata (breadth first levels) in the DAG 5338 5339 Level: developer 5340 5341 Notes: 5342 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5343 5344 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5345 5346 An empty mesh gives -1. 5347 5348 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5349 @*/ 5350 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5351 { 5352 DM_Plex *mesh = (DM_Plex *)dm->data; 5353 DMLabel label; 5354 PetscInt d = -1; 5355 5356 PetscFunctionBegin; 5357 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5358 PetscAssertPointer(depth, 2); 5359 if (mesh->tr) { 5360 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5361 } else { 5362 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5363 // Allow missing depths 5364 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5365 *depth = d; 5366 } 5367 PetscFunctionReturn(PETSC_SUCCESS); 5368 } 5369 5370 /*@ 5371 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5372 5373 Not Collective 5374 5375 Input Parameters: 5376 + dm - The `DMPLEX` object 5377 - depth - The requested depth 5378 5379 Output Parameters: 5380 + start - The first point at this `depth` 5381 - end - One beyond the last point at this `depth` 5382 5383 Level: developer 5384 5385 Notes: 5386 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5387 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5388 higher dimension, e.g., "edges". 5389 5390 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5391 @*/ 5392 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5393 { 5394 DM_Plex *mesh = (DM_Plex *)dm->data; 5395 DMLabel label; 5396 PetscInt pStart, pEnd; 5397 5398 PetscFunctionBegin; 5399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5400 if (start) { 5401 PetscAssertPointer(start, 3); 5402 *start = 0; 5403 } 5404 if (end) { 5405 PetscAssertPointer(end, 4); 5406 *end = 0; 5407 } 5408 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5409 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5410 if (depth < 0) { 5411 if (start) *start = pStart; 5412 if (end) *end = pEnd; 5413 PetscFunctionReturn(PETSC_SUCCESS); 5414 } 5415 if (mesh->tr) { 5416 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5417 } else { 5418 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5419 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5420 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5421 } 5422 PetscFunctionReturn(PETSC_SUCCESS); 5423 } 5424 5425 /*@ 5426 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5427 5428 Not Collective 5429 5430 Input Parameters: 5431 + dm - The `DMPLEX` object 5432 - height - The requested height 5433 5434 Output Parameters: 5435 + start - The first point at this `height` 5436 - end - One beyond the last point at this `height` 5437 5438 Level: developer 5439 5440 Notes: 5441 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5442 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5443 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5444 5445 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5446 @*/ 5447 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5448 { 5449 DMLabel label; 5450 PetscInt depth, pStart, pEnd; 5451 5452 PetscFunctionBegin; 5453 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5454 if (start) { 5455 PetscAssertPointer(start, 3); 5456 *start = 0; 5457 } 5458 if (end) { 5459 PetscAssertPointer(end, 4); 5460 *end = 0; 5461 } 5462 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5463 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5464 if (height < 0) { 5465 if (start) *start = pStart; 5466 if (end) *end = pEnd; 5467 PetscFunctionReturn(PETSC_SUCCESS); 5468 } 5469 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5470 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5471 else PetscCall(DMGetDimension(dm, &depth)); 5472 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5473 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5474 PetscFunctionReturn(PETSC_SUCCESS); 5475 } 5476 5477 /*@ 5478 DMPlexGetPointDepth - Get the `depth` of a given point 5479 5480 Not Collective 5481 5482 Input Parameters: 5483 + dm - The `DMPLEX` object 5484 - point - The point 5485 5486 Output Parameter: 5487 . depth - The depth of the `point` 5488 5489 Level: intermediate 5490 5491 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5492 @*/ 5493 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5494 { 5495 PetscFunctionBegin; 5496 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5497 PetscAssertPointer(depth, 3); 5498 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5499 PetscFunctionReturn(PETSC_SUCCESS); 5500 } 5501 5502 /*@ 5503 DMPlexGetPointHeight - Get the `height` of a given point 5504 5505 Not Collective 5506 5507 Input Parameters: 5508 + dm - The `DMPLEX` object 5509 - point - The point 5510 5511 Output Parameter: 5512 . height - The height of the `point` 5513 5514 Level: intermediate 5515 5516 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5517 @*/ 5518 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5519 { 5520 PetscInt n, pDepth; 5521 5522 PetscFunctionBegin; 5523 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5524 PetscAssertPointer(height, 3); 5525 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5526 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5527 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5528 PetscFunctionReturn(PETSC_SUCCESS); 5529 } 5530 5531 /*@ 5532 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5533 5534 Not Collective 5535 5536 Input Parameter: 5537 . dm - The `DMPLEX` object 5538 5539 Output Parameter: 5540 . celltypeLabel - The `DMLabel` recording cell polytope type 5541 5542 Level: developer 5543 5544 Note: 5545 This function will trigger automatica computation of cell types. This can be disabled by calling 5546 `DMCreateLabel`(dm, "celltype") beforehand. 5547 5548 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5549 @*/ 5550 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5551 { 5552 PetscFunctionBegin; 5553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5554 PetscAssertPointer(celltypeLabel, 2); 5555 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5556 *celltypeLabel = dm->celltypeLabel; 5557 PetscFunctionReturn(PETSC_SUCCESS); 5558 } 5559 5560 /*@ 5561 DMPlexGetCellType - Get the polytope type of a given cell 5562 5563 Not Collective 5564 5565 Input Parameters: 5566 + dm - The `DMPLEX` object 5567 - cell - The cell 5568 5569 Output Parameter: 5570 . celltype - The polytope type of the cell 5571 5572 Level: intermediate 5573 5574 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5575 @*/ 5576 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5577 { 5578 DM_Plex *mesh = (DM_Plex *)dm->data; 5579 DMLabel label; 5580 PetscInt ct; 5581 5582 PetscFunctionBegin; 5583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5584 PetscAssertPointer(celltype, 3); 5585 if (mesh->tr) { 5586 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5587 } else { 5588 PetscInt pStart, pEnd; 5589 5590 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5591 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5592 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5593 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5594 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5595 for (PetscInt p = pStart; p < pEnd; p++) { 5596 PetscCall(DMLabelGetValue(label, p, &ct)); 5597 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5598 } 5599 } 5600 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5601 if (PetscDefined(USE_DEBUG)) { 5602 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5603 PetscCall(DMLabelGetValue(label, cell, &ct)); 5604 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5605 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5606 } 5607 } 5608 PetscFunctionReturn(PETSC_SUCCESS); 5609 } 5610 5611 /*@ 5612 DMPlexSetCellType - Set the polytope type of a given cell 5613 5614 Not Collective 5615 5616 Input Parameters: 5617 + dm - The `DMPLEX` object 5618 . cell - The cell 5619 - celltype - The polytope type of the cell 5620 5621 Level: advanced 5622 5623 Note: 5624 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5625 is executed. This function will override the computed type. However, if automatic classification will not succeed 5626 and a user wants to manually specify all types, the classification must be disabled by calling 5627 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5628 5629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5630 @*/ 5631 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5632 { 5633 DM_Plex *mesh = (DM_Plex *)dm->data; 5634 DMLabel label; 5635 PetscInt pStart, pEnd; 5636 5637 PetscFunctionBegin; 5638 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5639 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5640 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5641 PetscCall(DMLabelSetValue(label, cell, celltype)); 5642 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5643 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5644 PetscFunctionReturn(PETSC_SUCCESS); 5645 } 5646 5647 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5648 { 5649 PetscSection section; 5650 PetscInt maxHeight; 5651 const char *prefix; 5652 5653 PetscFunctionBegin; 5654 PetscCall(DMClone(dm, cdm)); 5655 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5656 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5657 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5658 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5659 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5660 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5661 PetscCall(DMSetLocalSection(*cdm, section)); 5662 PetscCall(PetscSectionDestroy(§ion)); 5663 5664 PetscCall(DMSetNumFields(*cdm, 1)); 5665 PetscCall(DMCreateDS(*cdm)); 5666 (*cdm)->cloneOpts = PETSC_TRUE; 5667 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5668 PetscFunctionReturn(PETSC_SUCCESS); 5669 } 5670 5671 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5672 { 5673 Vec coordsLocal, cellCoordsLocal; 5674 DM coordsDM, cellCoordsDM; 5675 5676 PetscFunctionBegin; 5677 *field = NULL; 5678 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5679 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5680 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5681 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5682 if (coordsLocal && coordsDM) { 5683 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5684 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5685 } 5686 PetscFunctionReturn(PETSC_SUCCESS); 5687 } 5688 5689 /*@ 5690 DMPlexGetConeSection - Return a section which describes the layout of cone data 5691 5692 Not Collective 5693 5694 Input Parameter: 5695 . dm - The `DMPLEX` object 5696 5697 Output Parameter: 5698 . section - The `PetscSection` object 5699 5700 Level: developer 5701 5702 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5703 @*/ 5704 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5705 { 5706 DM_Plex *mesh = (DM_Plex *)dm->data; 5707 5708 PetscFunctionBegin; 5709 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5710 if (section) *section = mesh->coneSection; 5711 PetscFunctionReturn(PETSC_SUCCESS); 5712 } 5713 5714 /*@ 5715 DMPlexGetSupportSection - Return a section which describes the layout of support data 5716 5717 Not Collective 5718 5719 Input Parameter: 5720 . dm - The `DMPLEX` object 5721 5722 Output Parameter: 5723 . section - The `PetscSection` object 5724 5725 Level: developer 5726 5727 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5728 @*/ 5729 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5730 { 5731 DM_Plex *mesh = (DM_Plex *)dm->data; 5732 5733 PetscFunctionBegin; 5734 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5735 if (section) *section = mesh->supportSection; 5736 PetscFunctionReturn(PETSC_SUCCESS); 5737 } 5738 5739 /*@C 5740 DMPlexGetCones - Return cone data 5741 5742 Not Collective 5743 5744 Input Parameter: 5745 . dm - The `DMPLEX` object 5746 5747 Output Parameter: 5748 . cones - The cone for each point 5749 5750 Level: developer 5751 5752 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5753 @*/ 5754 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5755 { 5756 DM_Plex *mesh = (DM_Plex *)dm->data; 5757 5758 PetscFunctionBegin; 5759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5760 if (cones) *cones = mesh->cones; 5761 PetscFunctionReturn(PETSC_SUCCESS); 5762 } 5763 5764 /*@C 5765 DMPlexGetConeOrientations - Return cone orientation data 5766 5767 Not Collective 5768 5769 Input Parameter: 5770 . dm - The `DMPLEX` object 5771 5772 Output Parameter: 5773 . coneOrientations - The array of cone orientations for all points 5774 5775 Level: developer 5776 5777 Notes: 5778 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5779 as returned by `DMPlexGetConeOrientation()`. 5780 5781 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5782 5783 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5784 @*/ 5785 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5786 { 5787 DM_Plex *mesh = (DM_Plex *)dm->data; 5788 5789 PetscFunctionBegin; 5790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5791 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5792 PetscFunctionReturn(PETSC_SUCCESS); 5793 } 5794 5795 /* FEM Support */ 5796 5797 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5798 { 5799 PetscInt depth; 5800 5801 PetscFunctionBegin; 5802 PetscCall(DMPlexGetDepth(plex, &depth)); 5803 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5804 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5805 PetscFunctionReturn(PETSC_SUCCESS); 5806 } 5807 5808 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5809 { 5810 PetscInt depth; 5811 5812 PetscFunctionBegin; 5813 PetscCall(DMPlexGetDepth(plex, &depth)); 5814 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5815 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5816 PetscFunctionReturn(PETSC_SUCCESS); 5817 } 5818 5819 /* 5820 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5821 representing a line in the section. 5822 */ 5823 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5824 { 5825 PetscObject obj; 5826 PetscClassId id; 5827 PetscFE fe = NULL; 5828 5829 PetscFunctionBeginHot; 5830 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5831 PetscCall(DMGetField(dm, field, NULL, &obj)); 5832 PetscCall(PetscObjectGetClassId(obj, &id)); 5833 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5834 5835 if (!fe) { 5836 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5837 /* An order k SEM disc has k-1 dofs on an edge */ 5838 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5839 *k = *k / *Nc + 1; 5840 } else { 5841 PetscInt dual_space_size, dim; 5842 PetscDualSpace dsp; 5843 5844 PetscCall(DMGetDimension(dm, &dim)); 5845 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5846 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5847 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5848 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5849 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5850 } 5851 PetscFunctionReturn(PETSC_SUCCESS); 5852 } 5853 5854 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5855 { 5856 PetscFunctionBeginHot; 5857 if (tensor) { 5858 *dof = PetscPowInt(k + 1, dim); 5859 } else { 5860 switch (dim) { 5861 case 1: 5862 *dof = k + 1; 5863 break; 5864 case 2: 5865 *dof = ((k + 1) * (k + 2)) / 2; 5866 break; 5867 case 3: 5868 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5869 break; 5870 default: 5871 *dof = 0; 5872 } 5873 } 5874 PetscFunctionReturn(PETSC_SUCCESS); 5875 } 5876 5877 /*@ 5878 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5879 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5880 section provided (or the section of the `DM`). 5881 5882 Input Parameters: 5883 + dm - The `DM` 5884 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5885 - section - The `PetscSection` to reorder, or `NULL` for the default section 5886 5887 Example: 5888 A typical interpolated single-quad mesh might order points as 5889 .vb 5890 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5891 5892 v4 -- e6 -- v3 5893 | | 5894 e7 c0 e8 5895 | | 5896 v1 -- e5 -- v2 5897 .ve 5898 5899 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5900 dofs in the order of points, e.g., 5901 .vb 5902 c0 -> [0,1,2,3] 5903 v1 -> [4] 5904 ... 5905 e5 -> [8, 9] 5906 .ve 5907 5908 which corresponds to the dofs 5909 .vb 5910 6 10 11 7 5911 13 2 3 15 5912 12 0 1 14 5913 4 8 9 5 5914 .ve 5915 5916 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5917 .vb 5918 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5919 .ve 5920 5921 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5922 .vb 5923 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5924 .ve 5925 5926 Level: developer 5927 5928 Notes: 5929 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5930 degree of the basis. 5931 5932 This is required to run with libCEED. 5933 5934 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5935 @*/ 5936 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5937 { 5938 DMLabel label; 5939 PetscInt dim, depth = -1, eStart = -1, Nf; 5940 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5941 5942 PetscFunctionBegin; 5943 PetscCall(DMGetDimension(dm, &dim)); 5944 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5945 if (point < 0) { 5946 PetscInt sStart, sEnd; 5947 5948 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5949 point = sEnd - sStart ? sStart : point; 5950 } 5951 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5952 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5953 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5954 if (depth == 1) { 5955 eStart = point; 5956 } else if (depth == dim) { 5957 const PetscInt *cone; 5958 5959 PetscCall(DMPlexGetCone(dm, point, &cone)); 5960 if (dim == 2) eStart = cone[0]; 5961 else if (dim == 3) { 5962 const PetscInt *cone2; 5963 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5964 eStart = cone2[0]; 5965 } 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); 5966 } 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); 5967 5968 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5969 for (PetscInt d = 1; d <= dim; d++) { 5970 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5971 PetscInt *perm; 5972 5973 for (f = 0; f < Nf; ++f) { 5974 PetscInt dof; 5975 5976 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5977 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5978 if (!continuous && d < dim) continue; 5979 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5980 size += dof * Nc; 5981 } 5982 PetscCall(PetscMalloc1(size, &perm)); 5983 for (f = 0; f < Nf; ++f) { 5984 switch (d) { 5985 case 1: 5986 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5987 if (!continuous && d < dim) continue; 5988 /* 5989 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5990 We want [ vtx0; edge of length k-1; vtx1 ] 5991 */ 5992 if (continuous) { 5993 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5994 for (i = 0; i < k - 1; i++) 5995 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5996 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5997 foffset = offset; 5998 } else { 5999 PetscInt dof; 6000 6001 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6002 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6003 foffset = offset; 6004 } 6005 break; 6006 case 2: 6007 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6008 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6009 if (!continuous && d < dim) continue; 6010 /* The SEM order is 6011 6012 v_lb, {e_b}, v_rb, 6013 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6014 v_lt, reverse {e_t}, v_rt 6015 */ 6016 if (continuous) { 6017 const PetscInt of = 0; 6018 const PetscInt oeb = of + PetscSqr(k - 1); 6019 const PetscInt oer = oeb + (k - 1); 6020 const PetscInt oet = oer + (k - 1); 6021 const PetscInt oel = oet + (k - 1); 6022 const PetscInt ovlb = oel + (k - 1); 6023 const PetscInt ovrb = ovlb + 1; 6024 const PetscInt ovrt = ovrb + 1; 6025 const PetscInt ovlt = ovrt + 1; 6026 PetscInt o; 6027 6028 /* bottom */ 6029 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6030 for (o = oeb; o < oer; ++o) 6031 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6032 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6033 /* middle */ 6034 for (i = 0; i < k - 1; ++i) { 6035 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6036 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6037 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6038 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6039 } 6040 /* top */ 6041 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6042 for (o = oel - 1; o >= oet; --o) 6043 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6044 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6045 foffset = offset; 6046 } else { 6047 PetscInt dof; 6048 6049 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6050 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6051 foffset = offset; 6052 } 6053 break; 6054 case 3: 6055 /* The original hex closure is 6056 6057 {c, 6058 f_b, f_t, f_f, f_b, f_r, f_l, 6059 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6060 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6061 */ 6062 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6063 if (!continuous && d < dim) continue; 6064 /* The SEM order is 6065 Bottom Slice 6066 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6067 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6068 v_blb, {e_bb}, v_brb, 6069 6070 Middle Slice (j) 6071 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6072 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6073 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6074 6075 Top Slice 6076 v_tlf, {e_tf}, v_trf, 6077 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6078 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6079 */ 6080 if (continuous) { 6081 const PetscInt oc = 0; 6082 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6083 const PetscInt oft = ofb + PetscSqr(k - 1); 6084 const PetscInt off = oft + PetscSqr(k - 1); 6085 const PetscInt ofk = off + PetscSqr(k - 1); 6086 const PetscInt ofr = ofk + PetscSqr(k - 1); 6087 const PetscInt ofl = ofr + PetscSqr(k - 1); 6088 const PetscInt oebl = ofl + PetscSqr(k - 1); 6089 const PetscInt oebb = oebl + (k - 1); 6090 const PetscInt oebr = oebb + (k - 1); 6091 const PetscInt oebf = oebr + (k - 1); 6092 const PetscInt oetf = oebf + (k - 1); 6093 const PetscInt oetr = oetf + (k - 1); 6094 const PetscInt oetb = oetr + (k - 1); 6095 const PetscInt oetl = oetb + (k - 1); 6096 const PetscInt oerf = oetl + (k - 1); 6097 const PetscInt oelf = oerf + (k - 1); 6098 const PetscInt oelb = oelf + (k - 1); 6099 const PetscInt oerb = oelb + (k - 1); 6100 const PetscInt ovblf = oerb + (k - 1); 6101 const PetscInt ovblb = ovblf + 1; 6102 const PetscInt ovbrb = ovblb + 1; 6103 const PetscInt ovbrf = ovbrb + 1; 6104 const PetscInt ovtlf = ovbrf + 1; 6105 const PetscInt ovtrf = ovtlf + 1; 6106 const PetscInt ovtrb = ovtrf + 1; 6107 const PetscInt ovtlb = ovtrb + 1; 6108 PetscInt o, n; 6109 6110 /* Bottom Slice */ 6111 /* bottom */ 6112 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6113 for (o = oetf - 1; o >= oebf; --o) 6114 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6115 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6116 /* middle */ 6117 for (i = 0; i < k - 1; ++i) { 6118 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6119 for (n = 0; n < k - 1; ++n) { 6120 o = ofb + n * (k - 1) + i; 6121 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6122 } 6123 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6124 } 6125 /* top */ 6126 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6127 for (o = oebb; o < oebr; ++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] = ovbrb * Nc + c + foffset; 6130 6131 /* Middle Slice */ 6132 for (j = 0; j < k - 1; ++j) { 6133 /* bottom */ 6134 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6135 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++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] = (oerf + j) * Nc + c + foffset; 6138 /* middle */ 6139 for (i = 0; i < k - 1; ++i) { 6140 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6141 for (n = 0; n < k - 1; ++n) 6142 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6143 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6144 } 6145 /* top */ 6146 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6147 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --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] = (oerb + (k - 2) - j) * Nc + c + foffset; 6150 } 6151 6152 /* Top Slice */ 6153 /* bottom */ 6154 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6155 for (o = oetf; o < oetr; ++o) 6156 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6157 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6158 /* middle */ 6159 for (i = 0; i < k - 1; ++i) { 6160 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6161 for (n = 0; n < k - 1; ++n) 6162 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6163 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6164 } 6165 /* top */ 6166 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6167 for (o = oetl - 1; o >= oetb; --o) 6168 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6169 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6170 6171 foffset = offset; 6172 } else { 6173 PetscInt dof; 6174 6175 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6176 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6177 foffset = offset; 6178 } 6179 break; 6180 default: 6181 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6182 } 6183 } 6184 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6185 /* Check permutation */ 6186 { 6187 PetscInt *check; 6188 6189 PetscCall(PetscMalloc1(size, &check)); 6190 for (i = 0; i < size; ++i) { 6191 check[i] = -1; 6192 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6193 } 6194 for (i = 0; i < size; ++i) check[perm[i]] = i; 6195 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6196 PetscCall(PetscFree(check)); 6197 } 6198 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6199 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6200 PetscInt *loc_perm; 6201 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6202 for (PetscInt i = 0; i < size; i++) { 6203 loc_perm[i] = perm[i]; 6204 loc_perm[size + i] = size + perm[i]; 6205 } 6206 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6207 } 6208 } 6209 PetscFunctionReturn(PETSC_SUCCESS); 6210 } 6211 6212 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6213 { 6214 PetscDS prob; 6215 PetscInt depth, Nf, h; 6216 DMLabel label; 6217 6218 PetscFunctionBeginHot; 6219 PetscCall(DMGetDS(dm, &prob)); 6220 Nf = prob->Nf; 6221 label = dm->depthLabel; 6222 *dspace = NULL; 6223 if (field < Nf) { 6224 PetscObject disc = prob->disc[field]; 6225 6226 if (disc->classid == PETSCFE_CLASSID) { 6227 PetscDualSpace dsp; 6228 6229 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6230 PetscCall(DMLabelGetNumValues(label, &depth)); 6231 PetscCall(DMLabelGetValue(label, point, &h)); 6232 h = depth - 1 - h; 6233 if (h) { 6234 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6235 } else { 6236 *dspace = dsp; 6237 } 6238 } 6239 } 6240 PetscFunctionReturn(PETSC_SUCCESS); 6241 } 6242 6243 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6244 { 6245 PetscScalar *array; 6246 const PetscScalar *vArray; 6247 const PetscInt *cone, *coneO; 6248 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6249 6250 PetscFunctionBeginHot; 6251 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6252 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6253 PetscCall(DMPlexGetCone(dm, point, &cone)); 6254 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6255 if (!values || !*values) { 6256 if ((point >= pStart) && (point < pEnd)) { 6257 PetscInt dof; 6258 6259 PetscCall(PetscSectionGetDof(section, point, &dof)); 6260 size += dof; 6261 } 6262 for (p = 0; p < numPoints; ++p) { 6263 const PetscInt cp = cone[p]; 6264 PetscInt dof; 6265 6266 if ((cp < pStart) || (cp >= pEnd)) continue; 6267 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6268 size += dof; 6269 } 6270 if (!values) { 6271 if (csize) *csize = size; 6272 PetscFunctionReturn(PETSC_SUCCESS); 6273 } 6274 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6275 } else { 6276 array = *values; 6277 } 6278 size = 0; 6279 PetscCall(VecGetArrayRead(v, &vArray)); 6280 if ((point >= pStart) && (point < pEnd)) { 6281 PetscInt dof, off, d; 6282 const PetscScalar *varr; 6283 6284 PetscCall(PetscSectionGetDof(section, point, &dof)); 6285 PetscCall(PetscSectionGetOffset(section, point, &off)); 6286 varr = PetscSafePointerPlusOffset(vArray, off); 6287 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6288 size += dof; 6289 } 6290 for (p = 0; p < numPoints; ++p) { 6291 const PetscInt cp = cone[p]; 6292 PetscInt o = coneO[p]; 6293 PetscInt dof, off, d; 6294 const PetscScalar *varr; 6295 6296 if ((cp < pStart) || (cp >= pEnd)) continue; 6297 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6298 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6299 varr = PetscSafePointerPlusOffset(vArray, off); 6300 if (o >= 0) { 6301 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6302 } else { 6303 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6304 } 6305 size += dof; 6306 } 6307 PetscCall(VecRestoreArrayRead(v, &vArray)); 6308 if (!*values) { 6309 if (csize) *csize = size; 6310 *values = array; 6311 } else { 6312 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6313 *csize = size; 6314 } 6315 PetscFunctionReturn(PETSC_SUCCESS); 6316 } 6317 6318 /* Compress out points not in the section */ 6319 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6320 { 6321 const PetscInt np = *numPoints; 6322 PetscInt pStart, pEnd, p, q; 6323 6324 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6325 for (p = 0, q = 0; p < np; ++p) { 6326 const PetscInt r = points[p * 2]; 6327 if ((r >= pStart) && (r < pEnd)) { 6328 points[q * 2] = r; 6329 points[q * 2 + 1] = points[p * 2 + 1]; 6330 ++q; 6331 } 6332 } 6333 *numPoints = q; 6334 return PETSC_SUCCESS; 6335 } 6336 6337 /* Compressed closure does not apply closure permutation */ 6338 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6339 { 6340 const PetscInt *cla = NULL; 6341 PetscInt np, *pts = NULL; 6342 6343 PetscFunctionBeginHot; 6344 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6345 if (!ornt && *clPoints) { 6346 PetscInt dof, off; 6347 6348 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6349 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6350 PetscCall(ISGetIndices(*clPoints, &cla)); 6351 np = dof / 2; 6352 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6353 } else { 6354 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6355 PetscCall(CompressPoints_Private(section, &np, pts)); 6356 } 6357 *numPoints = np; 6358 *points = pts; 6359 *clp = cla; 6360 PetscFunctionReturn(PETSC_SUCCESS); 6361 } 6362 6363 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6364 { 6365 PetscFunctionBeginHot; 6366 if (!*clPoints) { 6367 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6368 } else { 6369 PetscCall(ISRestoreIndices(*clPoints, clp)); 6370 } 6371 *numPoints = 0; 6372 *points = NULL; 6373 *clSec = NULL; 6374 *clPoints = NULL; 6375 *clp = NULL; 6376 PetscFunctionReturn(PETSC_SUCCESS); 6377 } 6378 6379 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6380 { 6381 PetscInt offset = 0, p; 6382 const PetscInt **perms = NULL; 6383 const PetscScalar **flips = NULL; 6384 6385 PetscFunctionBeginHot; 6386 *size = 0; 6387 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6388 for (p = 0; p < numPoints; p++) { 6389 const PetscInt point = points[2 * p]; 6390 const PetscInt *perm = perms ? perms[p] : NULL; 6391 const PetscScalar *flip = flips ? flips[p] : NULL; 6392 PetscInt dof, off, d; 6393 const PetscScalar *varr; 6394 6395 PetscCall(PetscSectionGetDof(section, point, &dof)); 6396 PetscCall(PetscSectionGetOffset(section, point, &off)); 6397 varr = PetscSafePointerPlusOffset(vArray, off); 6398 if (clperm) { 6399 if (perm) { 6400 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6401 } else { 6402 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6403 } 6404 if (flip) { 6405 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6406 } 6407 } else { 6408 if (perm) { 6409 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6410 } else { 6411 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6412 } 6413 if (flip) { 6414 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6415 } 6416 } 6417 offset += dof; 6418 } 6419 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6420 *size = offset; 6421 PetscFunctionReturn(PETSC_SUCCESS); 6422 } 6423 6424 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[]) 6425 { 6426 PetscInt offset = 0, f; 6427 6428 PetscFunctionBeginHot; 6429 *size = 0; 6430 for (f = 0; f < numFields; ++f) { 6431 PetscInt p; 6432 const PetscInt **perms = NULL; 6433 const PetscScalar **flips = NULL; 6434 6435 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6436 for (p = 0; p < numPoints; p++) { 6437 const PetscInt point = points[2 * p]; 6438 PetscInt fdof, foff, b; 6439 const PetscScalar *varr; 6440 const PetscInt *perm = perms ? perms[p] : NULL; 6441 const PetscScalar *flip = flips ? flips[p] : NULL; 6442 6443 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6444 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6445 varr = &vArray[foff]; 6446 if (clperm) { 6447 if (perm) { 6448 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6449 } else { 6450 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6451 } 6452 if (flip) { 6453 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6454 } 6455 } else { 6456 if (perm) { 6457 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6458 } else { 6459 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6460 } 6461 if (flip) { 6462 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6463 } 6464 } 6465 offset += fdof; 6466 } 6467 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6468 } 6469 *size = offset; 6470 PetscFunctionReturn(PETSC_SUCCESS); 6471 } 6472 6473 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6474 { 6475 PetscSection clSection; 6476 IS clPoints; 6477 PetscInt *points = NULL; 6478 const PetscInt *clp, *perm = NULL; 6479 PetscInt depth, numFields, numPoints, asize; 6480 6481 PetscFunctionBeginHot; 6482 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6483 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6484 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6485 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6486 PetscCall(DMPlexGetDepth(dm, &depth)); 6487 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6488 if (depth == 1 && numFields < 2) { 6489 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6490 PetscFunctionReturn(PETSC_SUCCESS); 6491 } 6492 /* Get points */ 6493 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6494 /* Get sizes */ 6495 asize = 0; 6496 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6497 PetscInt dof; 6498 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6499 asize += dof; 6500 } 6501 if (values) { 6502 const PetscScalar *vArray; 6503 PetscInt size; 6504 6505 if (*values) { 6506 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); 6507 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6508 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6509 PetscCall(VecGetArrayRead(v, &vArray)); 6510 /* Get values */ 6511 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6512 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6513 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6514 /* Cleanup array */ 6515 PetscCall(VecRestoreArrayRead(v, &vArray)); 6516 } 6517 if (csize) *csize = asize; 6518 /* Cleanup points */ 6519 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6520 PetscFunctionReturn(PETSC_SUCCESS); 6521 } 6522 6523 /*@C 6524 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6525 6526 Not collective 6527 6528 Input Parameters: 6529 + dm - The `DM` 6530 . section - The section describing the layout in `v`, or `NULL` to use the default section 6531 . v - The local vector 6532 - point - The point in the `DM` 6533 6534 Input/Output Parameters: 6535 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6536 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6537 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6538 6539 Level: intermediate 6540 6541 Notes: 6542 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6543 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6544 assembly function, and a user may already have allocated storage for this operation. 6545 6546 A typical use could be 6547 .vb 6548 values = NULL; 6549 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6550 for (cl = 0; cl < clSize; ++cl) { 6551 <Compute on closure> 6552 } 6553 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6554 .ve 6555 or 6556 .vb 6557 PetscMalloc1(clMaxSize, &values); 6558 for (p = pStart; p < pEnd; ++p) { 6559 clSize = clMaxSize; 6560 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6561 for (cl = 0; cl < clSize; ++cl) { 6562 <Compute on closure> 6563 } 6564 } 6565 PetscFree(values); 6566 .ve 6567 6568 Fortran Notes: 6569 The `csize` argument is not present in the Fortran binding. 6570 6571 `values` must be declared with 6572 .vb 6573 PetscScalar,dimension(:),pointer :: values 6574 .ve 6575 and it will be allocated internally by PETSc to hold the values returned 6576 6577 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6578 @*/ 6579 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6580 { 6581 PetscFunctionBeginHot; 6582 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6583 PetscFunctionReturn(PETSC_SUCCESS); 6584 } 6585 6586 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6587 { 6588 DMLabel depthLabel; 6589 PetscSection clSection; 6590 IS clPoints; 6591 PetscScalar *array; 6592 const PetscScalar *vArray; 6593 PetscInt *points = NULL; 6594 const PetscInt *clp, *perm = NULL; 6595 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6596 6597 PetscFunctionBeginHot; 6598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6599 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6600 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6601 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6602 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6603 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6604 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6605 if (mdepth == 1 && numFields < 2) { 6606 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6607 PetscFunctionReturn(PETSC_SUCCESS); 6608 } 6609 /* Get points */ 6610 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6611 for (clsize = 0, p = 0; p < Np; p++) { 6612 PetscInt dof; 6613 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6614 clsize += dof; 6615 } 6616 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6617 /* Filter points */ 6618 for (p = 0; p < numPoints * 2; p += 2) { 6619 PetscInt dep; 6620 6621 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6622 if (dep != depth) continue; 6623 points[Np * 2 + 0] = points[p]; 6624 points[Np * 2 + 1] = points[p + 1]; 6625 ++Np; 6626 } 6627 /* Get array */ 6628 if (!values || !*values) { 6629 PetscInt asize = 0, dof; 6630 6631 for (p = 0; p < Np * 2; p += 2) { 6632 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6633 asize += dof; 6634 } 6635 if (!values) { 6636 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6637 if (csize) *csize = asize; 6638 PetscFunctionReturn(PETSC_SUCCESS); 6639 } 6640 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6641 } else { 6642 array = *values; 6643 } 6644 PetscCall(VecGetArrayRead(v, &vArray)); 6645 /* Get values */ 6646 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6647 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6648 /* Cleanup points */ 6649 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6650 /* Cleanup array */ 6651 PetscCall(VecRestoreArrayRead(v, &vArray)); 6652 if (!*values) { 6653 if (csize) *csize = size; 6654 *values = array; 6655 } else { 6656 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6657 *csize = size; 6658 } 6659 PetscFunctionReturn(PETSC_SUCCESS); 6660 } 6661 6662 /*@C 6663 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6664 6665 Not collective 6666 6667 Input Parameters: 6668 + dm - The `DM` 6669 . section - The section describing the layout in `v`, or `NULL` to use the default section 6670 . v - The local vector 6671 . point - The point in the `DM` 6672 . csize - The number of values in the closure, or `NULL` 6673 - values - The array of values 6674 6675 Level: intermediate 6676 6677 Note: 6678 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6679 6680 Fortran Note: 6681 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6682 6683 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6684 @*/ 6685 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6686 { 6687 PetscInt size = 0; 6688 6689 PetscFunctionBegin; 6690 /* Should work without recalculating size */ 6691 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6692 *values = NULL; 6693 PetscFunctionReturn(PETSC_SUCCESS); 6694 } 6695 6696 static inline void add(PetscScalar *x, PetscScalar y) 6697 { 6698 *x += y; 6699 } 6700 static inline void insert(PetscScalar *x, PetscScalar y) 6701 { 6702 *x = y; 6703 } 6704 6705 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[]) 6706 { 6707 PetscInt cdof; /* The number of constraints on this point */ 6708 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6709 PetscScalar *a; 6710 PetscInt off, cind = 0, k; 6711 6712 PetscFunctionBegin; 6713 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6714 PetscCall(PetscSectionGetOffset(section, point, &off)); 6715 a = &array[off]; 6716 if (!cdof || setBC) { 6717 if (clperm) { 6718 if (perm) { 6719 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6720 } else { 6721 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6722 } 6723 } else { 6724 if (perm) { 6725 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6726 } else { 6727 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6728 } 6729 } 6730 } else { 6731 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6732 if (clperm) { 6733 if (perm) { 6734 for (k = 0; k < dof; ++k) { 6735 if ((cind < cdof) && (k == cdofs[cind])) { 6736 ++cind; 6737 continue; 6738 } 6739 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6740 } 6741 } else { 6742 for (k = 0; k < dof; ++k) { 6743 if ((cind < cdof) && (k == cdofs[cind])) { 6744 ++cind; 6745 continue; 6746 } 6747 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6748 } 6749 } 6750 } else { 6751 if (perm) { 6752 for (k = 0; k < dof; ++k) { 6753 if ((cind < cdof) && (k == cdofs[cind])) { 6754 ++cind; 6755 continue; 6756 } 6757 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6758 } 6759 } else { 6760 for (k = 0; k < dof; ++k) { 6761 if ((cind < cdof) && (k == cdofs[cind])) { 6762 ++cind; 6763 continue; 6764 } 6765 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6766 } 6767 } 6768 } 6769 } 6770 PetscFunctionReturn(PETSC_SUCCESS); 6771 } 6772 6773 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[]) 6774 { 6775 PetscInt cdof; /* The number of constraints on this point */ 6776 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6777 PetscScalar *a; 6778 PetscInt off, cind = 0, k; 6779 6780 PetscFunctionBegin; 6781 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6782 PetscCall(PetscSectionGetOffset(section, point, &off)); 6783 a = &array[off]; 6784 if (cdof) { 6785 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6786 if (clperm) { 6787 if (perm) { 6788 for (k = 0; k < dof; ++k) { 6789 if ((cind < cdof) && (k == cdofs[cind])) { 6790 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6791 cind++; 6792 } 6793 } 6794 } else { 6795 for (k = 0; k < dof; ++k) { 6796 if ((cind < cdof) && (k == cdofs[cind])) { 6797 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6798 cind++; 6799 } 6800 } 6801 } 6802 } else { 6803 if (perm) { 6804 for (k = 0; k < dof; ++k) { 6805 if ((cind < cdof) && (k == cdofs[cind])) { 6806 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6807 cind++; 6808 } 6809 } 6810 } else { 6811 for (k = 0; k < dof; ++k) { 6812 if ((cind < cdof) && (k == cdofs[cind])) { 6813 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6814 cind++; 6815 } 6816 } 6817 } 6818 } 6819 } 6820 PetscFunctionReturn(PETSC_SUCCESS); 6821 } 6822 6823 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[]) 6824 { 6825 PetscScalar *a; 6826 PetscInt fdof, foff, fcdof, foffset = *offset; 6827 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6828 PetscInt cind = 0, b; 6829 6830 PetscFunctionBegin; 6831 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6832 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6833 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6834 a = &array[foff]; 6835 if (!fcdof || setBC) { 6836 if (clperm) { 6837 if (perm) { 6838 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6839 } else { 6840 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6841 } 6842 } else { 6843 if (perm) { 6844 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6845 } else { 6846 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6847 } 6848 } 6849 } else { 6850 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6851 if (clperm) { 6852 if (perm) { 6853 for (b = 0; b < fdof; b++) { 6854 if ((cind < fcdof) && (b == fcdofs[cind])) { 6855 ++cind; 6856 continue; 6857 } 6858 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6859 } 6860 } else { 6861 for (b = 0; b < fdof; b++) { 6862 if ((cind < fcdof) && (b == fcdofs[cind])) { 6863 ++cind; 6864 continue; 6865 } 6866 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6867 } 6868 } 6869 } else { 6870 if (perm) { 6871 for (b = 0; b < fdof; b++) { 6872 if ((cind < fcdof) && (b == fcdofs[cind])) { 6873 ++cind; 6874 continue; 6875 } 6876 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6877 } 6878 } else { 6879 for (b = 0; b < fdof; b++) { 6880 if ((cind < fcdof) && (b == fcdofs[cind])) { 6881 ++cind; 6882 continue; 6883 } 6884 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6885 } 6886 } 6887 } 6888 } 6889 *offset += fdof; 6890 PetscFunctionReturn(PETSC_SUCCESS); 6891 } 6892 6893 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[]) 6894 { 6895 PetscScalar *a; 6896 PetscInt fdof, foff, fcdof, foffset = *offset; 6897 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6898 PetscInt Nc, cind = 0, ncind = 0, b; 6899 PetscBool ncSet, fcSet; 6900 6901 PetscFunctionBegin; 6902 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6903 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6904 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6905 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6906 a = &array[foff]; 6907 if (fcdof) { 6908 /* We just override fcdof and fcdofs with Ncc and comps */ 6909 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6910 if (clperm) { 6911 if (perm) { 6912 if (comps) { 6913 for (b = 0; b < fdof; b++) { 6914 ncSet = fcSet = PETSC_FALSE; 6915 if (b % Nc == comps[ncind]) { 6916 ncind = (ncind + 1) % Ncc; 6917 ncSet = PETSC_TRUE; 6918 } 6919 if ((cind < fcdof) && (b == fcdofs[cind])) { 6920 ++cind; 6921 fcSet = PETSC_TRUE; 6922 } 6923 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6924 } 6925 } else { 6926 for (b = 0; b < fdof; b++) { 6927 if ((cind < fcdof) && (b == fcdofs[cind])) { 6928 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6929 ++cind; 6930 } 6931 } 6932 } 6933 } else { 6934 if (comps) { 6935 for (b = 0; b < fdof; b++) { 6936 ncSet = fcSet = PETSC_FALSE; 6937 if (b % Nc == comps[ncind]) { 6938 ncind = (ncind + 1) % Ncc; 6939 ncSet = PETSC_TRUE; 6940 } 6941 if ((cind < fcdof) && (b == fcdofs[cind])) { 6942 ++cind; 6943 fcSet = PETSC_TRUE; 6944 } 6945 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6946 } 6947 } else { 6948 for (b = 0; b < fdof; b++) { 6949 if ((cind < fcdof) && (b == fcdofs[cind])) { 6950 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6951 ++cind; 6952 } 6953 } 6954 } 6955 } 6956 } else { 6957 if (perm) { 6958 if (comps) { 6959 for (b = 0; b < fdof; b++) { 6960 ncSet = fcSet = PETSC_FALSE; 6961 if (b % Nc == comps[ncind]) { 6962 ncind = (ncind + 1) % Ncc; 6963 ncSet = PETSC_TRUE; 6964 } 6965 if ((cind < fcdof) && (b == fcdofs[cind])) { 6966 ++cind; 6967 fcSet = PETSC_TRUE; 6968 } 6969 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6970 } 6971 } else { 6972 for (b = 0; b < fdof; b++) { 6973 if ((cind < fcdof) && (b == fcdofs[cind])) { 6974 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6975 ++cind; 6976 } 6977 } 6978 } 6979 } else { 6980 if (comps) { 6981 for (b = 0; b < fdof; b++) { 6982 ncSet = fcSet = PETSC_FALSE; 6983 if (b % Nc == comps[ncind]) { 6984 ncind = (ncind + 1) % Ncc; 6985 ncSet = PETSC_TRUE; 6986 } 6987 if ((cind < fcdof) && (b == fcdofs[cind])) { 6988 ++cind; 6989 fcSet = PETSC_TRUE; 6990 } 6991 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6992 } 6993 } else { 6994 for (b = 0; b < fdof; b++) { 6995 if ((cind < fcdof) && (b == fcdofs[cind])) { 6996 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6997 ++cind; 6998 } 6999 } 7000 } 7001 } 7002 } 7003 } 7004 *offset += fdof; 7005 PetscFunctionReturn(PETSC_SUCCESS); 7006 } 7007 7008 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7009 { 7010 PetscScalar *array; 7011 const PetscInt *cone, *coneO; 7012 PetscInt pStart, pEnd, p, numPoints, off, dof; 7013 7014 PetscFunctionBeginHot; 7015 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7016 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7017 PetscCall(DMPlexGetCone(dm, point, &cone)); 7018 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7019 PetscCall(VecGetArray(v, &array)); 7020 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7021 const PetscInt cp = !p ? point : cone[p - 1]; 7022 const PetscInt o = !p ? 0 : coneO[p - 1]; 7023 7024 if ((cp < pStart) || (cp >= pEnd)) { 7025 dof = 0; 7026 continue; 7027 } 7028 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7029 /* ADD_VALUES */ 7030 { 7031 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7032 PetscScalar *a; 7033 PetscInt cdof, coff, cind = 0, k; 7034 7035 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7036 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7037 a = &array[coff]; 7038 if (!cdof) { 7039 if (o >= 0) { 7040 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7041 } else { 7042 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7043 } 7044 } else { 7045 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7046 if (o >= 0) { 7047 for (k = 0; k < dof; ++k) { 7048 if ((cind < cdof) && (k == cdofs[cind])) { 7049 ++cind; 7050 continue; 7051 } 7052 a[k] += values[off + k]; 7053 } 7054 } else { 7055 for (k = 0; k < dof; ++k) { 7056 if ((cind < cdof) && (k == cdofs[cind])) { 7057 ++cind; 7058 continue; 7059 } 7060 a[k] += values[off + dof - k - 1]; 7061 } 7062 } 7063 } 7064 } 7065 } 7066 PetscCall(VecRestoreArray(v, &array)); 7067 PetscFunctionReturn(PETSC_SUCCESS); 7068 } 7069 7070 /*@C 7071 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7072 7073 Not collective 7074 7075 Input Parameters: 7076 + dm - The `DM` 7077 . section - The section describing the layout in `v`, or `NULL` to use the default section 7078 . v - The local vector 7079 . point - The point in the `DM` 7080 . values - The array of values 7081 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7082 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7083 7084 Level: intermediate 7085 7086 Note: 7087 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7088 7089 Fortran Note: 7090 `values` must be declared with 7091 .vb 7092 PetscScalar,dimension(:),pointer :: values 7093 .ve 7094 7095 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7096 @*/ 7097 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7098 { 7099 PetscSection clSection; 7100 IS clPoints; 7101 PetscScalar *array; 7102 PetscInt *points = NULL; 7103 const PetscInt *clp, *clperm = NULL; 7104 PetscInt depth, numFields, numPoints, p, clsize; 7105 7106 PetscFunctionBeginHot; 7107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7108 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7109 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7110 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7111 PetscCall(DMPlexGetDepth(dm, &depth)); 7112 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7113 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7114 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7115 PetscFunctionReturn(PETSC_SUCCESS); 7116 } 7117 /* Get points */ 7118 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7119 for (clsize = 0, p = 0; p < numPoints; p++) { 7120 PetscInt dof; 7121 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7122 clsize += dof; 7123 } 7124 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7125 /* Get array */ 7126 PetscCall(VecGetArray(v, &array)); 7127 /* Get values */ 7128 if (numFields > 0) { 7129 PetscInt offset = 0, f; 7130 for (f = 0; f < numFields; ++f) { 7131 const PetscInt **perms = NULL; 7132 const PetscScalar **flips = NULL; 7133 7134 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7135 switch (mode) { 7136 case INSERT_VALUES: 7137 for (p = 0; p < numPoints; p++) { 7138 const PetscInt point = points[2 * p]; 7139 const PetscInt *perm = perms ? perms[p] : NULL; 7140 const PetscScalar *flip = flips ? flips[p] : NULL; 7141 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7142 } 7143 break; 7144 case INSERT_ALL_VALUES: 7145 for (p = 0; p < numPoints; p++) { 7146 const PetscInt point = points[2 * p]; 7147 const PetscInt *perm = perms ? perms[p] : NULL; 7148 const PetscScalar *flip = flips ? flips[p] : NULL; 7149 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7150 } 7151 break; 7152 case INSERT_BC_VALUES: 7153 for (p = 0; p < numPoints; p++) { 7154 const PetscInt point = points[2 * p]; 7155 const PetscInt *perm = perms ? perms[p] : NULL; 7156 const PetscScalar *flip = flips ? flips[p] : NULL; 7157 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7158 } 7159 break; 7160 case ADD_VALUES: 7161 for (p = 0; p < numPoints; p++) { 7162 const PetscInt point = points[2 * p]; 7163 const PetscInt *perm = perms ? perms[p] : NULL; 7164 const PetscScalar *flip = flips ? flips[p] : NULL; 7165 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7166 } 7167 break; 7168 case ADD_ALL_VALUES: 7169 for (p = 0; p < numPoints; p++) { 7170 const PetscInt point = points[2 * p]; 7171 const PetscInt *perm = perms ? perms[p] : NULL; 7172 const PetscScalar *flip = flips ? flips[p] : NULL; 7173 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7174 } 7175 break; 7176 case ADD_BC_VALUES: 7177 for (p = 0; p < numPoints; p++) { 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(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7182 } 7183 break; 7184 default: 7185 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7186 } 7187 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7188 } 7189 } else { 7190 PetscInt dof, off; 7191 const PetscInt **perms = NULL; 7192 const PetscScalar **flips = NULL; 7193 7194 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7195 switch (mode) { 7196 case INSERT_VALUES: 7197 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7198 const PetscInt point = points[2 * p]; 7199 const PetscInt *perm = perms ? perms[p] : NULL; 7200 const PetscScalar *flip = flips ? flips[p] : NULL; 7201 PetscCall(PetscSectionGetDof(section, point, &dof)); 7202 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7203 } 7204 break; 7205 case INSERT_ALL_VALUES: 7206 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7207 const PetscInt point = points[2 * p]; 7208 const PetscInt *perm = perms ? perms[p] : NULL; 7209 const PetscScalar *flip = flips ? flips[p] : NULL; 7210 PetscCall(PetscSectionGetDof(section, point, &dof)); 7211 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7212 } 7213 break; 7214 case INSERT_BC_VALUES: 7215 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7216 const PetscInt point = points[2 * p]; 7217 const PetscInt *perm = perms ? perms[p] : NULL; 7218 const PetscScalar *flip = flips ? flips[p] : NULL; 7219 PetscCall(PetscSectionGetDof(section, point, &dof)); 7220 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7221 } 7222 break; 7223 case ADD_VALUES: 7224 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7225 const PetscInt point = points[2 * p]; 7226 const PetscInt *perm = perms ? perms[p] : NULL; 7227 const PetscScalar *flip = flips ? flips[p] : NULL; 7228 PetscCall(PetscSectionGetDof(section, point, &dof)); 7229 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7230 } 7231 break; 7232 case ADD_ALL_VALUES: 7233 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7234 const PetscInt point = points[2 * p]; 7235 const PetscInt *perm = perms ? perms[p] : NULL; 7236 const PetscScalar *flip = flips ? flips[p] : NULL; 7237 PetscCall(PetscSectionGetDof(section, point, &dof)); 7238 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7239 } 7240 break; 7241 case ADD_BC_VALUES: 7242 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7243 const PetscInt point = points[2 * p]; 7244 const PetscInt *perm = perms ? perms[p] : NULL; 7245 const PetscScalar *flip = flips ? flips[p] : NULL; 7246 PetscCall(PetscSectionGetDof(section, point, &dof)); 7247 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7248 } 7249 break; 7250 default: 7251 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7252 } 7253 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7254 } 7255 /* Cleanup points */ 7256 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7257 /* Cleanup array */ 7258 PetscCall(VecRestoreArray(v, &array)); 7259 PetscFunctionReturn(PETSC_SUCCESS); 7260 } 7261 7262 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7263 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7264 { 7265 PetscFunctionBegin; 7266 *contains = PETSC_TRUE; 7267 if (label) { 7268 PetscInt fdof; 7269 7270 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7271 if (!*contains) { 7272 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7273 *offset += fdof; 7274 PetscFunctionReturn(PETSC_SUCCESS); 7275 } 7276 } 7277 PetscFunctionReturn(PETSC_SUCCESS); 7278 } 7279 7280 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7281 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) 7282 { 7283 PetscSection clSection; 7284 IS clPoints; 7285 PetscScalar *array; 7286 PetscInt *points = NULL; 7287 const PetscInt *clp; 7288 PetscInt numFields, numPoints, p; 7289 PetscInt offset = 0, f; 7290 7291 PetscFunctionBeginHot; 7292 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7293 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7294 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7295 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7296 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7297 /* Get points */ 7298 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7299 /* Get array */ 7300 PetscCall(VecGetArray(v, &array)); 7301 /* Get values */ 7302 for (f = 0; f < numFields; ++f) { 7303 const PetscInt **perms = NULL; 7304 const PetscScalar **flips = NULL; 7305 PetscBool contains; 7306 7307 if (!fieldActive[f]) { 7308 for (p = 0; p < numPoints * 2; p += 2) { 7309 PetscInt fdof; 7310 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7311 offset += fdof; 7312 } 7313 continue; 7314 } 7315 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7316 switch (mode) { 7317 case INSERT_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(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7325 } 7326 break; 7327 case INSERT_ALL_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, insert, PETSC_TRUE, NULL, values, &offset, array)); 7335 } 7336 break; 7337 case INSERT_BC_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(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7345 } 7346 break; 7347 case ADD_VALUES: 7348 for (p = 0; p < numPoints; p++) { 7349 const PetscInt point = points[2 * p]; 7350 const PetscInt *perm = perms ? perms[p] : NULL; 7351 const PetscScalar *flip = flips ? flips[p] : NULL; 7352 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7353 if (!contains) continue; 7354 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7355 } 7356 break; 7357 case ADD_ALL_VALUES: 7358 for (p = 0; p < numPoints; p++) { 7359 const PetscInt point = points[2 * p]; 7360 const PetscInt *perm = perms ? perms[p] : NULL; 7361 const PetscScalar *flip = flips ? flips[p] : NULL; 7362 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7363 if (!contains) continue; 7364 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7365 } 7366 break; 7367 default: 7368 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7369 } 7370 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7371 } 7372 /* Cleanup points */ 7373 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7374 /* Cleanup array */ 7375 PetscCall(VecRestoreArray(v, &array)); 7376 PetscFunctionReturn(PETSC_SUCCESS); 7377 } 7378 7379 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7380 { 7381 PetscMPIInt rank; 7382 PetscInt i, j; 7383 7384 PetscFunctionBegin; 7385 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7386 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7387 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7388 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7389 numCIndices = numCIndices ? numCIndices : numRIndices; 7390 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7391 for (i = 0; i < numRIndices; i++) { 7392 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7393 for (j = 0; j < numCIndices; j++) { 7394 #if defined(PETSC_USE_COMPLEX) 7395 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7396 #else 7397 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7398 #endif 7399 } 7400 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7401 } 7402 PetscFunctionReturn(PETSC_SUCCESS); 7403 } 7404 7405 /* 7406 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7407 7408 Input Parameters: 7409 + section - The section for this data layout 7410 . islocal - Is the section (and thus indices being requested) local or global? 7411 . point - The point contributing dofs with these indices 7412 . off - The global offset of this point 7413 . loff - The local offset of each field 7414 . setBC - The flag determining whether to include indices of boundary values 7415 . perm - A permutation of the dofs on this point, or NULL 7416 - indperm - A permutation of the entire indices array, or NULL 7417 7418 Output Parameter: 7419 . indices - Indices for dofs on this point 7420 7421 Level: developer 7422 7423 Note: The indices could be local or global, depending on the value of 'off'. 7424 */ 7425 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7426 { 7427 PetscInt dof; /* The number of unknowns on this point */ 7428 PetscInt cdof; /* The number of constraints on this point */ 7429 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7430 PetscInt cind = 0, k; 7431 7432 PetscFunctionBegin; 7433 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7434 PetscCall(PetscSectionGetDof(section, point, &dof)); 7435 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7436 if (!cdof || setBC) { 7437 for (k = 0; k < dof; ++k) { 7438 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7439 const PetscInt ind = indperm ? indperm[preind] : preind; 7440 7441 indices[ind] = off + k; 7442 } 7443 } else { 7444 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7445 for (k = 0; k < dof; ++k) { 7446 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7447 const PetscInt ind = indperm ? indperm[preind] : preind; 7448 7449 if ((cind < cdof) && (k == cdofs[cind])) { 7450 /* Insert check for returning constrained indices */ 7451 indices[ind] = -(off + k + 1); 7452 ++cind; 7453 } else { 7454 indices[ind] = off + k - (islocal ? 0 : cind); 7455 } 7456 } 7457 } 7458 *loff += dof; 7459 PetscFunctionReturn(PETSC_SUCCESS); 7460 } 7461 7462 /* 7463 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7464 7465 Input Parameters: 7466 + section - a section (global or local) 7467 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7468 . point - point within section 7469 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7470 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7471 . setBC - identify constrained (boundary condition) points via involution. 7472 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7473 . permsoff - offset 7474 - indperm - index permutation 7475 7476 Output Parameter: 7477 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7478 . indices - array to hold indices (as defined by section) of each dof associated with point 7479 7480 Notes: 7481 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7482 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7483 in the local vector. 7484 7485 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7486 significant). It is invalid to call with a global section and setBC=true. 7487 7488 Developer Note: 7489 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7490 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7491 offset could be obtained from the section instead of passing it explicitly as we do now. 7492 7493 Example: 7494 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7495 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7496 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7497 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. 7498 7499 Level: developer 7500 */ 7501 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[]) 7502 { 7503 PetscInt numFields, foff, f; 7504 7505 PetscFunctionBegin; 7506 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7507 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7508 for (f = 0, foff = 0; f < numFields; ++f) { 7509 PetscInt fdof, cfdof; 7510 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7511 PetscInt cind = 0, b; 7512 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7513 7514 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7515 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7516 if (!cfdof || setBC) { 7517 for (b = 0; b < fdof; ++b) { 7518 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7519 const PetscInt ind = indperm ? indperm[preind] : preind; 7520 7521 indices[ind] = off + foff + b; 7522 } 7523 } else { 7524 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7525 for (b = 0; b < fdof; ++b) { 7526 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7527 const PetscInt ind = indperm ? indperm[preind] : preind; 7528 7529 if ((cind < cfdof) && (b == fcdofs[cind])) { 7530 indices[ind] = -(off + foff + b + 1); 7531 ++cind; 7532 } else { 7533 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7534 } 7535 } 7536 } 7537 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7538 foffs[f] += fdof; 7539 } 7540 PetscFunctionReturn(PETSC_SUCCESS); 7541 } 7542 7543 /* 7544 This version believes the globalSection offsets for each field, rather than just the point offset 7545 7546 . foffs - The offset into 'indices' for each field, since it is segregated by field 7547 7548 Notes: 7549 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7550 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7551 */ 7552 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7553 { 7554 PetscInt numFields, foff, f; 7555 7556 PetscFunctionBegin; 7557 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7558 for (f = 0; f < numFields; ++f) { 7559 PetscInt fdof, cfdof; 7560 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7561 PetscInt cind = 0, b; 7562 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7563 7564 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7565 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7566 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7567 if (!cfdof) { 7568 for (b = 0; b < fdof; ++b) { 7569 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7570 const PetscInt ind = indperm ? indperm[preind] : preind; 7571 7572 indices[ind] = foff + b; 7573 } 7574 } else { 7575 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7576 for (b = 0; b < fdof; ++b) { 7577 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7578 const PetscInt ind = indperm ? indperm[preind] : preind; 7579 7580 if ((cind < cfdof) && (b == fcdofs[cind])) { 7581 indices[ind] = -(foff + b + 1); 7582 ++cind; 7583 } else { 7584 indices[ind] = foff + b - cind; 7585 } 7586 } 7587 } 7588 foffs[f] += fdof; 7589 } 7590 PetscFunctionReturn(PETSC_SUCCESS); 7591 } 7592 7593 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7594 { 7595 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7596 7597 PetscFunctionBegin; 7598 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7599 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7600 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7601 for (PetscInt p = 0; p < nPoints; p++) { 7602 PetscInt b = pnts[2 * p]; 7603 PetscInt bSecDof = 0, bOff; 7604 PetscInt cSecDof = 0; 7605 PetscSection indices_section; 7606 7607 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7608 if (!bSecDof) continue; 7609 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7610 indices_section = cSecDof > 0 ? cSec : section; 7611 if (numFields) { 7612 PetscInt fStart[32], fEnd[32]; 7613 7614 fStart[0] = 0; 7615 fEnd[0] = 0; 7616 for (PetscInt f = 0; f < numFields; f++) { 7617 PetscInt fDof = 0; 7618 7619 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7620 fStart[f + 1] = fStart[f] + fDof; 7621 fEnd[f + 1] = fStart[f + 1]; 7622 } 7623 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7624 // only apply permutations on one side 7625 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7626 for (PetscInt f = 0; f < numFields; f++) { 7627 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7628 } 7629 } else { 7630 PetscInt bEnd = 0; 7631 7632 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7633 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7634 7635 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7636 } 7637 } 7638 PetscFunctionReturn(PETSC_SUCCESS); 7639 } 7640 7641 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[]) 7642 { 7643 Mat cMat; 7644 PetscSection aSec, cSec; 7645 IS aIS; 7646 PetscInt aStart = -1, aEnd = -1; 7647 PetscInt sStart = -1, sEnd = -1; 7648 PetscInt cStart = -1, cEnd = -1; 7649 const PetscInt *anchors; 7650 PetscInt numFields, p; 7651 PetscInt newNumPoints = 0, newNumIndices = 0; 7652 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7653 PetscInt oldOffsets[32]; 7654 PetscInt newOffsets[32]; 7655 PetscInt oldOffsetsCopy[32]; 7656 PetscInt newOffsetsCopy[32]; 7657 PetscScalar *modMat = NULL; 7658 PetscBool anyConstrained = PETSC_FALSE; 7659 7660 PetscFunctionBegin; 7661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7662 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7663 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7664 7665 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7666 /* if there are point-to-point constraints */ 7667 if (aSec) { 7668 PetscCall(PetscArrayzero(newOffsets, 32)); 7669 PetscCall(PetscArrayzero(oldOffsets, 32)); 7670 PetscCall(ISGetIndices(aIS, &anchors)); 7671 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7672 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7673 /* figure out how many points are going to be in the new element matrix 7674 * (we allow double counting, because it's all just going to be summed 7675 * into the global matrix anyway) */ 7676 for (p = 0; p < 2 * numPoints; p += 2) { 7677 PetscInt b = points[p]; 7678 PetscInt bDof = 0, bSecDof = 0; 7679 7680 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7681 if (!bSecDof) continue; 7682 7683 for (PetscInt f = 0; f < numFields; f++) { 7684 PetscInt fDof = 0; 7685 7686 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7687 oldOffsets[f + 1] += fDof; 7688 } 7689 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7690 if (bDof) { 7691 /* this point is constrained */ 7692 /* it is going to be replaced by its anchors */ 7693 PetscInt bOff, q; 7694 7695 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7696 for (q = 0; q < bDof; q++) { 7697 PetscInt a = anchors[bOff + q]; 7698 PetscInt aDof = 0; 7699 7700 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7701 if (aDof) { 7702 anyConstrained = PETSC_TRUE; 7703 newNumPoints += 1; 7704 } 7705 newNumIndices += aDof; 7706 for (PetscInt f = 0; f < numFields; ++f) { 7707 PetscInt fDof = 0; 7708 7709 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7710 newOffsets[f + 1] += fDof; 7711 } 7712 } 7713 } else { 7714 /* this point is not constrained */ 7715 newNumPoints++; 7716 newNumIndices += bSecDof; 7717 for (PetscInt f = 0; f < numFields; ++f) { 7718 PetscInt fDof; 7719 7720 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7721 newOffsets[f + 1] += fDof; 7722 } 7723 } 7724 } 7725 } 7726 if (!anyConstrained) { 7727 if (outNumPoints) *outNumPoints = 0; 7728 if (outNumIndices) *outNumIndices = 0; 7729 if (outPoints) *outPoints = NULL; 7730 if (outMat) *outMat = NULL; 7731 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7732 PetscFunctionReturn(PETSC_SUCCESS); 7733 } 7734 7735 if (outNumPoints) *outNumPoints = newNumPoints; 7736 if (outNumIndices) *outNumIndices = newNumIndices; 7737 7738 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7739 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7740 7741 if (!outPoints && !outMat) { 7742 if (offsets) { 7743 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7744 } 7745 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7746 PetscFunctionReturn(PETSC_SUCCESS); 7747 } 7748 7749 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7750 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7751 7752 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7753 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7754 7755 /* output arrays */ 7756 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7757 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7758 7759 // get the new Points 7760 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7761 PetscInt b = points[2 * p]; 7762 PetscInt bDof = 0, bSecDof = 0, bOff; 7763 7764 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7765 if (!bSecDof) continue; 7766 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7767 if (bDof) { 7768 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7769 for (PetscInt q = 0; q < bDof; q++) { 7770 PetscInt a = anchors[bOff + q], aDof = 0; 7771 7772 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7773 if (aDof) { 7774 newPoints[2 * newP] = a; 7775 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7776 newP++; 7777 } 7778 } 7779 } else { 7780 newPoints[2 * newP] = b; 7781 newPoints[2 * newP + 1] = points[2 * p + 1]; 7782 newP++; 7783 } 7784 } 7785 7786 if (outMat) { 7787 PetscScalar *tmpMat; 7788 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7789 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7790 7791 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7792 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7793 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7794 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7795 7796 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7797 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7798 7799 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7800 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7801 7802 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7803 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7804 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7805 // for each field, insert the anchor modification into modMat 7806 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7807 PetscInt fStart = oldOffsets[f]; 7808 PetscInt fNewStart = newOffsets[f]; 7809 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7810 PetscInt b = points[2 * p]; 7811 PetscInt bDof = 0, bSecDof = 0, bOff; 7812 7813 if (b >= sStart && b < sEnd) { 7814 if (numFields) { 7815 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7816 } else { 7817 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7818 } 7819 } 7820 if (!bSecDof) continue; 7821 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7822 if (bDof) { 7823 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7824 for (PetscInt q = 0; q < bDof; q++, newP++) { 7825 PetscInt a = anchors[bOff + q], aDof = 0; 7826 7827 if (a >= sStart && a < sEnd) { 7828 if (numFields) { 7829 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7830 } else { 7831 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7832 } 7833 } 7834 if (aDof) { 7835 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7836 for (PetscInt d = 0; d < bSecDof; d++) { 7837 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7838 } 7839 } 7840 oNew += aDof; 7841 } 7842 } else { 7843 // Insert the identity matrix in this block 7844 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7845 oNew += bSecDof; 7846 newP++; 7847 } 7848 o += bSecDof; 7849 } 7850 } 7851 7852 *outMat = modMat; 7853 7854 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7855 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7856 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7857 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7858 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7859 } 7860 PetscCall(ISRestoreIndices(aIS, &anchors)); 7861 7862 /* output */ 7863 if (outPoints) { 7864 *outPoints = newPoints; 7865 } else { 7866 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7867 } 7868 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7869 PetscFunctionReturn(PETSC_SUCCESS); 7870 } 7871 7872 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) 7873 { 7874 PetscScalar *modMat = NULL; 7875 PetscInt newNumIndices = -1; 7876 7877 PetscFunctionBegin; 7878 /* 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. 7879 modMat is that matrix C */ 7880 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7881 if (outNumIndices) *outNumIndices = newNumIndices; 7882 if (modMat) { 7883 const PetscScalar *newValues = values; 7884 7885 if (multiplyRight) { 7886 PetscScalar *newNewValues = NULL; 7887 PetscBLASInt M, N, K; 7888 PetscScalar a = 1.0, b = 0.0; 7889 7890 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); 7891 7892 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7893 PetscCall(PetscBLASIntCast(numRows, &N)); 7894 PetscCall(PetscBLASIntCast(numIndices, &K)); 7895 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7896 // row-major to column-major conversion, right multiplication becomes left multiplication 7897 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7898 numCols = newNumIndices; 7899 newValues = newNewValues; 7900 } 7901 7902 if (multiplyLeft) { 7903 PetscScalar *newNewValues = NULL; 7904 PetscBLASInt M, N, K; 7905 PetscScalar a = 1.0, b = 0.0; 7906 7907 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); 7908 7909 PetscCall(PetscBLASIntCast(numCols, &M)); 7910 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7911 PetscCall(PetscBLASIntCast(numIndices, &K)); 7912 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7913 // row-major to column-major conversion, left multiplication becomes right multiplication 7914 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7915 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7916 newValues = newNewValues; 7917 } 7918 *outValues = (PetscScalar *)newValues; 7919 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7920 } 7921 PetscFunctionReturn(PETSC_SUCCESS); 7922 } 7923 7924 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) 7925 { 7926 PetscFunctionBegin; 7927 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7928 PetscFunctionReturn(PETSC_SUCCESS); 7929 } 7930 7931 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7932 { 7933 /* Closure ordering */ 7934 PetscSection clSection; 7935 IS clPoints; 7936 const PetscInt *clp; 7937 PetscInt *points; 7938 PetscInt Ncl, Ni = 0; 7939 7940 PetscFunctionBeginHot; 7941 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7942 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7943 PetscInt dof; 7944 7945 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7946 Ni += dof; 7947 } 7948 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7949 *closureSize = Ni; 7950 PetscFunctionReturn(PETSC_SUCCESS); 7951 } 7952 7953 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) 7954 { 7955 /* Closure ordering */ 7956 PetscSection clSection; 7957 IS clPoints; 7958 const PetscInt *clp; 7959 PetscInt *points; 7960 const PetscInt *clperm = NULL; 7961 /* Dof permutation and sign flips */ 7962 const PetscInt **perms[32] = {NULL}; 7963 const PetscScalar **flips[32] = {NULL}; 7964 PetscScalar *valCopy = NULL; 7965 /* Hanging node constraints */ 7966 PetscInt *pointsC = NULL; 7967 PetscScalar *valuesC = NULL; 7968 PetscInt NclC, NiC; 7969 7970 PetscInt *idx; 7971 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7972 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7973 PetscInt idxStart, idxEnd; 7974 PetscInt nRows, nCols; 7975 7976 PetscFunctionBeginHot; 7977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7978 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7979 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7980 PetscAssertPointer(numRows, 6); 7981 PetscAssertPointer(numCols, 7); 7982 if (indices) PetscAssertPointer(indices, 8); 7983 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7984 if (values) PetscAssertPointer(values, 10); 7985 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7986 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7987 PetscCall(PetscArrayzero(offsets, 32)); 7988 /* 1) Get points in closure */ 7989 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7990 if (useClPerm) { 7991 PetscInt depth, clsize; 7992 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7993 for (clsize = 0, p = 0; p < Ncl; p++) { 7994 PetscInt dof; 7995 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7996 clsize += dof; 7997 } 7998 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7999 } 8000 /* 2) Get number of indices on these points and field offsets from section */ 8001 for (p = 0; p < Ncl * 2; p += 2) { 8002 PetscInt dof, fdof; 8003 8004 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8005 for (f = 0; f < Nf; ++f) { 8006 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8007 offsets[f + 1] += fdof; 8008 } 8009 Ni += dof; 8010 } 8011 if (*numRows == -1) *numRows = Ni; 8012 if (*numCols == -1) *numCols = Ni; 8013 nRows = *numRows; 8014 nCols = *numCols; 8015 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8016 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8017 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8018 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8019 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8020 for (f = 0; f < PetscMax(1, Nf); ++f) { 8021 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8022 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8023 /* may need to apply sign changes to the element matrix */ 8024 if (values && flips[f]) { 8025 PetscInt foffset = offsets[f]; 8026 8027 for (p = 0; p < Ncl; ++p) { 8028 PetscInt pnt = points[2 * p], fdof; 8029 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8030 8031 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8032 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8033 if (flip) { 8034 PetscInt i, j, k; 8035 8036 if (!valCopy) { 8037 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8038 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8039 *values = valCopy; 8040 } 8041 for (i = 0; i < fdof; ++i) { 8042 PetscScalar fval = flip[i]; 8043 8044 if (multiplyRight) { 8045 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8046 } 8047 if (multiplyLeft) { 8048 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8049 } 8050 } 8051 } 8052 foffset += fdof; 8053 } 8054 } 8055 } 8056 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8057 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8058 if (NclC) { 8059 if (multiplyRight) { *numCols = nCols = NiC; } 8060 if (multiplyLeft) { *numRows = nRows = NiC; } 8061 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8062 for (f = 0; f < PetscMax(1, Nf); ++f) { 8063 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8064 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8065 } 8066 for (f = 0; f < PetscMax(1, Nf); ++f) { 8067 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8068 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8069 } 8070 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8071 Ncl = NclC; 8072 Ni = NiC; 8073 points = pointsC; 8074 if (values) *values = valuesC; 8075 } 8076 /* 5) Calculate indices */ 8077 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8078 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8079 if (Nf) { 8080 PetscInt idxOff; 8081 PetscBool useFieldOffsets; 8082 8083 if (outOffsets) { 8084 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8085 } 8086 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8087 if (useFieldOffsets) { 8088 for (p = 0; p < Ncl; ++p) { 8089 const PetscInt pnt = points[p * 2]; 8090 8091 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8092 } 8093 } else { 8094 for (p = 0; p < Ncl; ++p) { 8095 const PetscInt pnt = points[p * 2]; 8096 8097 if (pnt < idxStart || pnt >= idxEnd) continue; 8098 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8099 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8100 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8101 * global section. */ 8102 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8103 } 8104 } 8105 } else { 8106 PetscInt off = 0, idxOff; 8107 8108 for (p = 0; p < Ncl; ++p) { 8109 const PetscInt pnt = points[p * 2]; 8110 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8111 8112 if (pnt < idxStart || pnt >= idxEnd) continue; 8113 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8114 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8115 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8116 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8117 } 8118 } 8119 /* 6) Cleanup */ 8120 for (f = 0; f < PetscMax(1, Nf); ++f) { 8121 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8122 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8123 } 8124 if (NclC) { 8125 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8126 } else { 8127 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8128 } 8129 8130 if (indices) *indices = idx; 8131 PetscFunctionReturn(PETSC_SUCCESS); 8132 } 8133 8134 /*@C 8135 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8136 8137 Not collective 8138 8139 Input Parameters: 8140 + dm - The `DM` 8141 . section - The `PetscSection` describing the points (a local section) 8142 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8143 . point - The point defining the closure 8144 - useClPerm - Use the closure point permutation if available 8145 8146 Output Parameters: 8147 + numIndices - The number of dof indices in the closure of point with the input sections 8148 . indices - The dof indices 8149 . outOffsets - Array to write the field offsets into, or `NULL` 8150 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8151 8152 Level: advanced 8153 8154 Notes: 8155 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8156 8157 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8158 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8159 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8160 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8161 indices (with the above semantics) are implied. 8162 8163 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8164 `PetscSection`, `DMGetGlobalSection()` 8165 @*/ 8166 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8167 { 8168 PetscInt numRows = -1, numCols = -1; 8169 8170 PetscFunctionBeginHot; 8171 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8172 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8173 *numIndices = numRows; 8174 PetscFunctionReturn(PETSC_SUCCESS); 8175 } 8176 8177 /*@C 8178 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8179 8180 Not collective 8181 8182 Input Parameters: 8183 + dm - The `DM` 8184 . section - The `PetscSection` describing the points (a local section) 8185 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8186 . point - The point defining the closure 8187 - useClPerm - Use the closure point permutation if available 8188 8189 Output Parameters: 8190 + numIndices - The number of dof indices in the closure of point with the input sections 8191 . indices - The dof indices 8192 . outOffsets - Array to write the field offsets into, or `NULL` 8193 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8194 8195 Level: advanced 8196 8197 Notes: 8198 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8199 8200 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8201 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8202 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8203 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8204 indices (with the above semantics) are implied. 8205 8206 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8207 @*/ 8208 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8209 { 8210 PetscFunctionBegin; 8211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8212 PetscAssertPointer(indices, 7); 8213 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8214 PetscFunctionReturn(PETSC_SUCCESS); 8215 } 8216 8217 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8218 { 8219 DM_Plex *mesh = (DM_Plex *)dm->data; 8220 PetscInt *indices; 8221 PetscInt numIndices; 8222 const PetscScalar *valuesOrig = values; 8223 PetscErrorCode ierr; 8224 8225 PetscFunctionBegin; 8226 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8227 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8228 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8229 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8230 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8231 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8232 8233 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8234 8235 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8236 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8237 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8238 if (ierr) { 8239 PetscMPIInt rank; 8240 8241 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8242 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8243 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8244 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8245 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8246 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8247 } 8248 if (mesh->printFEM > 1) { 8249 PetscInt i; 8250 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8251 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8252 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8253 } 8254 8255 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8256 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8257 PetscFunctionReturn(PETSC_SUCCESS); 8258 } 8259 8260 /*@C 8261 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8262 8263 Not collective 8264 8265 Input Parameters: 8266 + dm - The `DM` 8267 . section - The section describing the layout in `v`, or `NULL` to use the default section 8268 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8269 . A - The matrix 8270 . point - The point in the `DM` 8271 . values - The array of values 8272 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8273 8274 Level: intermediate 8275 8276 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8277 @*/ 8278 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8279 { 8280 PetscFunctionBegin; 8281 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8282 PetscFunctionReturn(PETSC_SUCCESS); 8283 } 8284 8285 /*@C 8286 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8287 8288 Not collective 8289 8290 Input Parameters: 8291 + dmRow - The `DM` for the row fields 8292 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8293 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8294 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8295 . dmCol - The `DM` for the column fields 8296 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8297 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8298 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8299 . A - The matrix 8300 . point - The point in the `DM` 8301 . values - The array of values 8302 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8303 8304 Level: intermediate 8305 8306 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8307 @*/ 8308 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) 8309 { 8310 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8311 PetscInt *indicesRow, *indicesCol; 8312 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8313 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8314 8315 PetscErrorCode ierr; 8316 8317 PetscFunctionBegin; 8318 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8319 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8320 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8321 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8322 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8323 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8324 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8325 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8326 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8327 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8328 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8329 8330 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8331 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8332 valuesV1 = valuesV0; 8333 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8334 valuesV2 = valuesV1; 8335 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8336 8337 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8338 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8339 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8340 if (ierr) { 8341 PetscMPIInt rank; 8342 8343 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8344 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8345 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8346 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8347 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8348 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8349 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8350 } 8351 8352 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8353 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8354 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8355 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8356 PetscFunctionReturn(PETSC_SUCCESS); 8357 } 8358 8359 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8360 { 8361 DM_Plex *mesh = (DM_Plex *)dmf->data; 8362 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8363 PetscInt *cpoints = NULL; 8364 PetscInt *findices, *cindices; 8365 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8366 PetscInt foffsets[32], coffsets[32]; 8367 DMPolytopeType ct; 8368 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8369 PetscErrorCode ierr; 8370 8371 PetscFunctionBegin; 8372 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8373 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8374 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8375 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8376 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8377 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8378 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8379 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8380 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8381 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8382 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8383 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8384 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8385 PetscCall(PetscArrayzero(foffsets, 32)); 8386 PetscCall(PetscArrayzero(coffsets, 32)); 8387 /* Column indices */ 8388 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8389 maxFPoints = numCPoints; 8390 /* Compress out points not in the section */ 8391 /* TODO: Squeeze out points with 0 dof as well */ 8392 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8393 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8394 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8395 cpoints[q * 2] = cpoints[p]; 8396 cpoints[q * 2 + 1] = cpoints[p + 1]; 8397 ++q; 8398 } 8399 } 8400 numCPoints = q; 8401 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8402 PetscInt fdof; 8403 8404 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8405 if (!dof) continue; 8406 for (f = 0; f < numFields; ++f) { 8407 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8408 coffsets[f + 1] += fdof; 8409 } 8410 numCIndices += dof; 8411 } 8412 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8413 /* Row indices */ 8414 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8415 { 8416 DMPlexTransform tr; 8417 DMPolytopeType *rct; 8418 PetscInt *rsize, *rcone, *rornt, Nt; 8419 8420 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8421 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8422 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8423 numSubcells = rsize[Nt - 1]; 8424 PetscCall(DMPlexTransformDestroy(&tr)); 8425 } 8426 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8427 for (r = 0, q = 0; r < numSubcells; ++r) { 8428 /* TODO Map from coarse to fine cells */ 8429 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8430 /* Compress out points not in the section */ 8431 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8432 for (p = 0; p < numFPoints * 2; p += 2) { 8433 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8434 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8435 if (!dof) continue; 8436 for (s = 0; s < q; ++s) 8437 if (fpoints[p] == ftotpoints[s * 2]) break; 8438 if (s < q) continue; 8439 ftotpoints[q * 2] = fpoints[p]; 8440 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8441 ++q; 8442 } 8443 } 8444 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8445 } 8446 numFPoints = q; 8447 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8448 PetscInt fdof; 8449 8450 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8451 if (!dof) continue; 8452 for (f = 0; f < numFields; ++f) { 8453 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8454 foffsets[f + 1] += fdof; 8455 } 8456 numFIndices += dof; 8457 } 8458 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8459 8460 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8461 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8462 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8463 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8464 if (numFields) { 8465 const PetscInt **permsF[32] = {NULL}; 8466 const PetscInt **permsC[32] = {NULL}; 8467 8468 for (f = 0; f < numFields; f++) { 8469 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8470 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8471 } 8472 for (p = 0; p < numFPoints; p++) { 8473 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8474 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8475 } 8476 for (p = 0; p < numCPoints; p++) { 8477 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8478 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8479 } 8480 for (f = 0; f < numFields; f++) { 8481 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8482 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8483 } 8484 } else { 8485 const PetscInt **permsF = NULL; 8486 const PetscInt **permsC = NULL; 8487 8488 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8489 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8490 for (p = 0, off = 0; p < numFPoints; p++) { 8491 const PetscInt *perm = permsF ? permsF[p] : NULL; 8492 8493 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8494 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8495 } 8496 for (p = 0, off = 0; p < numCPoints; p++) { 8497 const PetscInt *perm = permsC ? permsC[p] : NULL; 8498 8499 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8500 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8501 } 8502 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8503 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8504 } 8505 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8506 /* TODO: flips */ 8507 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8508 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8509 if (ierr) { 8510 PetscMPIInt rank; 8511 8512 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8513 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8514 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8515 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8516 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8517 } 8518 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8519 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8520 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8521 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8522 PetscFunctionReturn(PETSC_SUCCESS); 8523 } 8524 8525 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8526 { 8527 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8528 PetscInt *cpoints = NULL; 8529 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8530 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8531 DMPolytopeType ct; 8532 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8533 8534 PetscFunctionBegin; 8535 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8536 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8537 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8538 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8539 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8540 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8541 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8542 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8543 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8544 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8545 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8546 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8547 /* Column indices */ 8548 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8549 maxFPoints = numCPoints; 8550 /* Compress out points not in the section */ 8551 /* TODO: Squeeze out points with 0 dof as well */ 8552 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8553 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8554 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8555 cpoints[q * 2] = cpoints[p]; 8556 cpoints[q * 2 + 1] = cpoints[p + 1]; 8557 ++q; 8558 } 8559 } 8560 numCPoints = q; 8561 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8562 PetscInt fdof; 8563 8564 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8565 if (!dof) continue; 8566 for (f = 0; f < numFields; ++f) { 8567 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8568 coffsets[f + 1] += fdof; 8569 } 8570 numCIndices += dof; 8571 } 8572 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8573 /* Row indices */ 8574 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8575 { 8576 DMPlexTransform tr; 8577 DMPolytopeType *rct; 8578 PetscInt *rsize, *rcone, *rornt, Nt; 8579 8580 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8581 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8582 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8583 numSubcells = rsize[Nt - 1]; 8584 PetscCall(DMPlexTransformDestroy(&tr)); 8585 } 8586 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8587 for (r = 0, q = 0; r < numSubcells; ++r) { 8588 /* TODO Map from coarse to fine cells */ 8589 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8590 /* Compress out points not in the section */ 8591 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8592 for (p = 0; p < numFPoints * 2; p += 2) { 8593 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8594 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8595 if (!dof) continue; 8596 for (s = 0; s < q; ++s) 8597 if (fpoints[p] == ftotpoints[s * 2]) break; 8598 if (s < q) continue; 8599 ftotpoints[q * 2] = fpoints[p]; 8600 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8601 ++q; 8602 } 8603 } 8604 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8605 } 8606 numFPoints = q; 8607 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8608 PetscInt fdof; 8609 8610 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8611 if (!dof) continue; 8612 for (f = 0; f < numFields; ++f) { 8613 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8614 foffsets[f + 1] += fdof; 8615 } 8616 numFIndices += dof; 8617 } 8618 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8619 8620 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8621 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8622 if (numFields) { 8623 const PetscInt **permsF[32] = {NULL}; 8624 const PetscInt **permsC[32] = {NULL}; 8625 8626 for (f = 0; f < numFields; f++) { 8627 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8628 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8629 } 8630 for (p = 0; p < numFPoints; p++) { 8631 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8632 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8633 } 8634 for (p = 0; p < numCPoints; p++) { 8635 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8636 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8637 } 8638 for (f = 0; f < numFields; f++) { 8639 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8640 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8641 } 8642 } else { 8643 const PetscInt **permsF = NULL; 8644 const PetscInt **permsC = NULL; 8645 8646 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8647 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8648 for (p = 0, off = 0; p < numFPoints; p++) { 8649 const PetscInt *perm = permsF ? permsF[p] : NULL; 8650 8651 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8652 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8653 } 8654 for (p = 0, off = 0; p < numCPoints; p++) { 8655 const PetscInt *perm = permsC ? permsC[p] : NULL; 8656 8657 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8658 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8659 } 8660 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8661 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8662 } 8663 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8664 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8665 PetscFunctionReturn(PETSC_SUCCESS); 8666 } 8667 8668 /*@ 8669 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8670 8671 Input Parameter: 8672 . dm - The `DMPLEX` object 8673 8674 Output Parameter: 8675 . cellHeight - The height of a cell 8676 8677 Level: developer 8678 8679 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8680 @*/ 8681 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8682 { 8683 DM_Plex *mesh = (DM_Plex *)dm->data; 8684 8685 PetscFunctionBegin; 8686 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8687 PetscAssertPointer(cellHeight, 2); 8688 *cellHeight = mesh->vtkCellHeight; 8689 PetscFunctionReturn(PETSC_SUCCESS); 8690 } 8691 8692 /*@ 8693 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8694 8695 Input Parameters: 8696 + dm - The `DMPLEX` object 8697 - cellHeight - The height of a cell 8698 8699 Level: developer 8700 8701 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8702 @*/ 8703 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8704 { 8705 DM_Plex *mesh = (DM_Plex *)dm->data; 8706 8707 PetscFunctionBegin; 8708 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8709 mesh->vtkCellHeight = cellHeight; 8710 PetscFunctionReturn(PETSC_SUCCESS); 8711 } 8712 8713 /*@ 8714 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8715 8716 Input Parameters: 8717 + dm - The `DMPLEX` object 8718 - ct - The `DMPolytopeType` of the cell 8719 8720 Output Parameters: 8721 + start - The first cell of this type, or `NULL` 8722 - end - The upper bound on this celltype, or `NULL` 8723 8724 Level: advanced 8725 8726 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8727 @*/ 8728 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8729 { 8730 DM_Plex *mesh = (DM_Plex *)dm->data; 8731 DMLabel label; 8732 PetscInt pStart, pEnd; 8733 8734 PetscFunctionBegin; 8735 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8736 if (start) { 8737 PetscAssertPointer(start, 3); 8738 *start = 0; 8739 } 8740 if (end) { 8741 PetscAssertPointer(end, 4); 8742 *end = 0; 8743 } 8744 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8745 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8746 if (mesh->tr) { 8747 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8748 } else { 8749 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8750 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8751 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8752 } 8753 PetscFunctionReturn(PETSC_SUCCESS); 8754 } 8755 8756 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8757 { 8758 PetscSection section, globalSection; 8759 PetscInt *numbers, p; 8760 8761 PetscFunctionBegin; 8762 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8763 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8764 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8765 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8766 PetscCall(PetscSectionSetUp(section)); 8767 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8768 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8769 for (p = pStart; p < pEnd; ++p) { 8770 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8771 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8772 else numbers[p - pStart] += shift; 8773 } 8774 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8775 if (globalSize) { 8776 PetscLayout layout; 8777 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8778 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8779 PetscCall(PetscLayoutDestroy(&layout)); 8780 } 8781 PetscCall(PetscSectionDestroy(§ion)); 8782 PetscCall(PetscSectionDestroy(&globalSection)); 8783 PetscFunctionReturn(PETSC_SUCCESS); 8784 } 8785 8786 /*@ 8787 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8788 8789 Input Parameters: 8790 + dm - The `DMPLEX` object 8791 - includeAll - Whether to include all cells, or just the simplex and box cells 8792 8793 Output Parameter: 8794 . globalCellNumbers - Global cell numbers for all cells on this process 8795 8796 Level: developer 8797 8798 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8799 @*/ 8800 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8801 { 8802 PetscInt cellHeight, cStart, cEnd; 8803 8804 PetscFunctionBegin; 8805 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8806 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8807 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8808 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8809 PetscFunctionReturn(PETSC_SUCCESS); 8810 } 8811 8812 /*@ 8813 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8814 8815 Input Parameter: 8816 . dm - The `DMPLEX` object 8817 8818 Output Parameter: 8819 . globalCellNumbers - Global cell numbers for all cells on this process 8820 8821 Level: developer 8822 8823 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8824 @*/ 8825 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8826 { 8827 DM_Plex *mesh = (DM_Plex *)dm->data; 8828 8829 PetscFunctionBegin; 8830 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8831 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8832 *globalCellNumbers = mesh->globalCellNumbers; 8833 PetscFunctionReturn(PETSC_SUCCESS); 8834 } 8835 8836 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8837 { 8838 PetscInt vStart, vEnd; 8839 8840 PetscFunctionBegin; 8841 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8842 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8843 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8844 PetscFunctionReturn(PETSC_SUCCESS); 8845 } 8846 8847 /*@ 8848 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8849 8850 Input Parameter: 8851 . dm - The `DMPLEX` object 8852 8853 Output Parameter: 8854 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8855 8856 Level: developer 8857 8858 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8859 @*/ 8860 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8861 { 8862 DM_Plex *mesh = (DM_Plex *)dm->data; 8863 8864 PetscFunctionBegin; 8865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8866 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8867 *globalVertexNumbers = mesh->globalVertexNumbers; 8868 PetscFunctionReturn(PETSC_SUCCESS); 8869 } 8870 8871 /*@ 8872 DMPlexCreatePointNumbering - Create a global numbering for all points. 8873 8874 Collective 8875 8876 Input Parameter: 8877 . dm - The `DMPLEX` object 8878 8879 Output Parameter: 8880 . globalPointNumbers - Global numbers for all points on this process 8881 8882 Level: developer 8883 8884 Notes: 8885 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8886 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8887 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8888 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8889 8890 The partitioned mesh is 8891 ``` 8892 (2)--0--(3)--1--(4) (1)--0--(2) 8893 ``` 8894 and its global numbering is 8895 ``` 8896 (3)--0--(4)--1--(5)--2--(6) 8897 ``` 8898 Then the global numbering is provided as 8899 ``` 8900 [0] Number of indices in set 5 8901 [0] 0 0 8902 [0] 1 1 8903 [0] 2 3 8904 [0] 3 4 8905 [0] 4 -6 8906 [1] Number of indices in set 3 8907 [1] 0 2 8908 [1] 1 5 8909 [1] 2 6 8910 ``` 8911 8912 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8913 @*/ 8914 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8915 { 8916 IS nums[4]; 8917 PetscInt depths[4], gdepths[4], starts[4]; 8918 PetscInt depth, d, shift = 0; 8919 PetscBool empty = PETSC_FALSE; 8920 8921 PetscFunctionBegin; 8922 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8923 PetscCall(DMPlexGetDepth(dm, &depth)); 8924 // For unstratified meshes use dim instead of depth 8925 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8926 // If any stratum is empty, we must mark all empty 8927 for (d = 0; d <= depth; ++d) { 8928 PetscInt end; 8929 8930 depths[d] = depth - d; 8931 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8932 if (!(starts[d] - end)) empty = PETSC_TRUE; 8933 } 8934 if (empty) 8935 for (d = 0; d <= depth; ++d) { 8936 depths[d] = -1; 8937 starts[d] = -1; 8938 } 8939 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8940 PetscCallMPI(MPIU_Allreduce(depths, gdepths, (PetscMPIInt)(depth + 1), MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8941 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]); 8942 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8943 for (d = 0; d <= depth; ++d) { 8944 PetscInt pStart, pEnd, gsize; 8945 8946 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8947 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8948 shift += gsize; 8949 } 8950 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8951 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8952 PetscFunctionReturn(PETSC_SUCCESS); 8953 } 8954 8955 /*@ 8956 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8957 8958 Collective 8959 8960 Input Parameter: 8961 . dm - The `DMPLEX` object 8962 8963 Output Parameter: 8964 . globalEdgeNumbers - Global numbers for all edges on this process 8965 8966 Level: developer 8967 8968 Notes: 8969 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). 8970 8971 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8972 @*/ 8973 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8974 { 8975 PetscSF sf; 8976 PetscInt eStart, eEnd; 8977 8978 PetscFunctionBegin; 8979 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8980 PetscCall(DMGetPointSF(dm, &sf)); 8981 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8982 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8983 PetscFunctionReturn(PETSC_SUCCESS); 8984 } 8985 8986 /*@ 8987 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8988 8989 Input Parameter: 8990 . dm - The `DMPLEX` object 8991 8992 Output Parameter: 8993 . ranks - The rank field 8994 8995 Options Database Key: 8996 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8997 8998 Level: intermediate 8999 9000 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9001 @*/ 9002 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9003 { 9004 DM rdm; 9005 PetscFE fe; 9006 PetscScalar *r; 9007 PetscMPIInt rank; 9008 DMPolytopeType ct; 9009 PetscInt dim, cStart, cEnd, c; 9010 PetscBool simplex; 9011 9012 PetscFunctionBeginUser; 9013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9014 PetscAssertPointer(ranks, 2); 9015 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9016 PetscCall(DMClone(dm, &rdm)); 9017 PetscCall(DMGetDimension(rdm, &dim)); 9018 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9019 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9020 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9021 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9022 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9023 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9024 PetscCall(PetscFEDestroy(&fe)); 9025 PetscCall(DMCreateDS(rdm)); 9026 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9027 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9028 PetscCall(VecGetArray(*ranks, &r)); 9029 for (c = cStart; c < cEnd; ++c) { 9030 PetscScalar *lr; 9031 9032 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9033 if (lr) *lr = rank; 9034 } 9035 PetscCall(VecRestoreArray(*ranks, &r)); 9036 PetscCall(DMDestroy(&rdm)); 9037 PetscFunctionReturn(PETSC_SUCCESS); 9038 } 9039 9040 /*@ 9041 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9042 9043 Input Parameters: 9044 + dm - The `DMPLEX` 9045 - label - The `DMLabel` 9046 9047 Output Parameter: 9048 . val - The label value field 9049 9050 Options Database Key: 9051 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9052 9053 Level: intermediate 9054 9055 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9056 @*/ 9057 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9058 { 9059 DM rdm, plex; 9060 Vec lval; 9061 PetscSection section; 9062 PetscFE fe; 9063 PetscScalar *v; 9064 PetscInt dim, pStart, pEnd, p, cStart; 9065 DMPolytopeType ct; 9066 char name[PETSC_MAX_PATH_LEN]; 9067 const char *lname, *prefix; 9068 9069 PetscFunctionBeginUser; 9070 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9071 PetscAssertPointer(label, 2); 9072 PetscAssertPointer(val, 3); 9073 PetscCall(DMClone(dm, &rdm)); 9074 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9075 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9076 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9077 PetscCall(DMDestroy(&plex)); 9078 PetscCall(DMGetDimension(rdm, &dim)); 9079 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9080 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9081 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9082 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9083 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9084 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9085 PetscCall(PetscFEDestroy(&fe)); 9086 PetscCall(DMCreateDS(rdm)); 9087 PetscCall(DMCreateGlobalVector(rdm, val)); 9088 PetscCall(DMCreateLocalVector(rdm, &lval)); 9089 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9090 PetscCall(DMGetLocalSection(rdm, §ion)); 9091 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9092 PetscCall(VecGetArray(lval, &v)); 9093 for (p = pStart; p < pEnd; ++p) { 9094 PetscInt cval, dof, off; 9095 9096 PetscCall(PetscSectionGetDof(section, p, &dof)); 9097 if (!dof) continue; 9098 PetscCall(DMLabelGetValue(label, p, &cval)); 9099 PetscCall(PetscSectionGetOffset(section, p, &off)); 9100 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9101 } 9102 PetscCall(VecRestoreArray(lval, &v)); 9103 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9104 PetscCall(VecDestroy(&lval)); 9105 PetscCall(DMDestroy(&rdm)); 9106 PetscFunctionReturn(PETSC_SUCCESS); 9107 } 9108 9109 /*@ 9110 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9111 9112 Input Parameter: 9113 . dm - The `DMPLEX` object 9114 9115 Level: developer 9116 9117 Notes: 9118 This is a useful diagnostic when creating meshes programmatically. 9119 9120 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9121 9122 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9123 @*/ 9124 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9125 { 9126 PetscSection coneSection, supportSection; 9127 const PetscInt *cone, *support; 9128 PetscInt coneSize, c, supportSize, s; 9129 PetscInt pStart, pEnd, p, pp, csize, ssize; 9130 PetscBool storagecheck = PETSC_TRUE; 9131 9132 PetscFunctionBegin; 9133 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9134 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9135 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9136 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9137 /* Check that point p is found in the support of its cone points, and vice versa */ 9138 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9139 for (p = pStart; p < pEnd; ++p) { 9140 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9141 PetscCall(DMPlexGetCone(dm, p, &cone)); 9142 for (c = 0; c < coneSize; ++c) { 9143 PetscBool dup = PETSC_FALSE; 9144 PetscInt d; 9145 for (d = c - 1; d >= 0; --d) { 9146 if (cone[c] == cone[d]) { 9147 dup = PETSC_TRUE; 9148 break; 9149 } 9150 } 9151 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9152 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9153 for (s = 0; s < supportSize; ++s) { 9154 if (support[s] == p) break; 9155 } 9156 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9157 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9158 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9159 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9160 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9161 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9162 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9163 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]); 9164 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9165 } 9166 } 9167 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9168 if (p != pp) { 9169 storagecheck = PETSC_FALSE; 9170 continue; 9171 } 9172 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9173 PetscCall(DMPlexGetSupport(dm, p, &support)); 9174 for (s = 0; s < supportSize; ++s) { 9175 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9176 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9177 for (c = 0; c < coneSize; ++c) { 9178 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9179 if (cone[c] != pp) { 9180 c = 0; 9181 break; 9182 } 9183 if (cone[c] == p) break; 9184 } 9185 if (c >= coneSize) { 9186 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9187 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9188 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9189 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9190 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9191 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9192 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9193 } 9194 } 9195 } 9196 if (storagecheck) { 9197 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9198 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9199 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9200 } 9201 PetscFunctionReturn(PETSC_SUCCESS); 9202 } 9203 9204 /* 9205 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. 9206 */ 9207 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9208 { 9209 DMPolytopeType cct; 9210 PetscInt ptpoints[4]; 9211 const PetscInt *cone, *ccone, *ptcone; 9212 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9213 9214 PetscFunctionBegin; 9215 *unsplit = 0; 9216 switch (ct) { 9217 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9218 ptpoints[npt++] = c; 9219 break; 9220 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9221 PetscCall(DMPlexGetCone(dm, c, &cone)); 9222 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9223 for (cp = 0; cp < coneSize; ++cp) { 9224 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9225 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9226 } 9227 break; 9228 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9229 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9230 PetscCall(DMPlexGetCone(dm, c, &cone)); 9231 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9232 for (cp = 0; cp < coneSize; ++cp) { 9233 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9234 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9235 for (ccp = 0; ccp < cconeSize; ++ccp) { 9236 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9237 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9238 PetscInt p; 9239 for (p = 0; p < npt; ++p) 9240 if (ptpoints[p] == ccone[ccp]) break; 9241 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9242 } 9243 } 9244 } 9245 break; 9246 default: 9247 break; 9248 } 9249 for (pt = 0; pt < npt; ++pt) { 9250 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9251 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9252 } 9253 PetscFunctionReturn(PETSC_SUCCESS); 9254 } 9255 9256 /*@ 9257 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9258 9259 Input Parameters: 9260 + dm - The `DMPLEX` object 9261 - cellHeight - Normally 0 9262 9263 Level: developer 9264 9265 Notes: 9266 This is a useful diagnostic when creating meshes programmatically. 9267 Currently applicable only to homogeneous simplex or tensor meshes. 9268 9269 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9270 9271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9272 @*/ 9273 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9274 { 9275 DMPlexInterpolatedFlag interp; 9276 DMPolytopeType ct; 9277 PetscInt vStart, vEnd, cStart, cEnd, c; 9278 9279 PetscFunctionBegin; 9280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9281 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9282 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9283 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9284 for (c = cStart; c < cEnd; ++c) { 9285 PetscInt *closure = NULL; 9286 PetscInt coneSize, closureSize, cl, Nv = 0; 9287 9288 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9289 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9290 if (interp == DMPLEX_INTERPOLATED_FULL) { 9291 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9292 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)); 9293 } 9294 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9295 for (cl = 0; cl < closureSize * 2; cl += 2) { 9296 const PetscInt p = closure[cl]; 9297 if ((p >= vStart) && (p < vEnd)) ++Nv; 9298 } 9299 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9300 /* Special Case: Tensor faces with identified vertices */ 9301 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9302 PetscInt unsplit; 9303 9304 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9305 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9306 } 9307 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)); 9308 } 9309 PetscFunctionReturn(PETSC_SUCCESS); 9310 } 9311 9312 /*@ 9313 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9314 9315 Collective 9316 9317 Input Parameters: 9318 + dm - The `DMPLEX` object 9319 - cellHeight - Normally 0 9320 9321 Level: developer 9322 9323 Notes: 9324 This is a useful diagnostic when creating meshes programmatically. 9325 This routine is only relevant for meshes that are fully interpolated across all ranks. 9326 It will error out if a partially interpolated mesh is given on some rank. 9327 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9328 9329 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9330 9331 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9332 @*/ 9333 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9334 { 9335 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9336 DMPlexInterpolatedFlag interpEnum; 9337 9338 PetscFunctionBegin; 9339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9340 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9341 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9342 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9343 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9344 PetscFunctionReturn(PETSC_SUCCESS); 9345 } 9346 9347 PetscCall(DMGetDimension(dm, &dim)); 9348 PetscCall(DMPlexGetDepth(dm, &depth)); 9349 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9350 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9351 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9352 for (c = cStart; c < cEnd; ++c) { 9353 const PetscInt *cone, *ornt, *faceSizes, *faces; 9354 const DMPolytopeType *faceTypes; 9355 DMPolytopeType ct; 9356 PetscInt numFaces, coneSize, f; 9357 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9358 9359 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9360 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9361 if (unsplit) continue; 9362 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9363 PetscCall(DMPlexGetCone(dm, c, &cone)); 9364 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9365 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9366 for (cl = 0; cl < closureSize * 2; cl += 2) { 9367 const PetscInt p = closure[cl]; 9368 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9369 } 9370 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9371 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); 9372 for (f = 0; f < numFaces; ++f) { 9373 DMPolytopeType fct; 9374 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9375 9376 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9377 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9378 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9379 const PetscInt p = fclosure[cl]; 9380 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9381 } 9382 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]); 9383 for (v = 0; v < fnumCorners; ++v) { 9384 if (fclosure[v] != faces[fOff + v]) { 9385 PetscInt v1; 9386 9387 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9388 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9389 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9390 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9391 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9392 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]); 9393 } 9394 } 9395 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9396 fOff += faceSizes[f]; 9397 } 9398 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9399 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9400 } 9401 } 9402 PetscFunctionReturn(PETSC_SUCCESS); 9403 } 9404 9405 /*@ 9406 DMPlexCheckGeometry - Check the geometry of mesh cells 9407 9408 Input Parameter: 9409 . dm - The `DMPLEX` object 9410 9411 Level: developer 9412 9413 Notes: 9414 This is a useful diagnostic when creating meshes programmatically. 9415 9416 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9417 9418 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9419 @*/ 9420 PetscErrorCode DMPlexCheckGeometry(DM dm) 9421 { 9422 Vec coordinates; 9423 PetscReal detJ, J[9], refVol = 1.0; 9424 PetscReal vol; 9425 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9426 9427 PetscFunctionBegin; 9428 PetscCall(DMGetDimension(dm, &dim)); 9429 PetscCall(DMGetCoordinateDim(dm, &dE)); 9430 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9431 PetscCall(DMPlexGetDepth(dm, &depth)); 9432 for (d = 0; d < dim; ++d) refVol *= 2.0; 9433 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9434 /* Make sure local coordinates are created, because that step is collective */ 9435 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9436 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9437 for (c = cStart; c < cEnd; ++c) { 9438 DMPolytopeType ct; 9439 PetscInt unsplit; 9440 PetscBool ignoreZeroVol = PETSC_FALSE; 9441 9442 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9443 switch (ct) { 9444 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9445 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9446 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9447 ignoreZeroVol = PETSC_TRUE; 9448 break; 9449 default: 9450 break; 9451 } 9452 switch (ct) { 9453 case DM_POLYTOPE_TRI_PRISM: 9454 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9455 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9456 case DM_POLYTOPE_PYRAMID: 9457 continue; 9458 default: 9459 break; 9460 } 9461 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9462 if (unsplit) continue; 9463 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9464 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); 9465 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9466 /* This should work with periodicity since DG coordinates should be used */ 9467 if (depth > 1) { 9468 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9469 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); 9470 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9471 } 9472 } 9473 PetscFunctionReturn(PETSC_SUCCESS); 9474 } 9475 9476 /*@ 9477 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9478 9479 Collective 9480 9481 Input Parameters: 9482 + dm - The `DMPLEX` object 9483 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9484 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9485 9486 Level: developer 9487 9488 Notes: 9489 This is mainly intended for debugging/testing purposes. 9490 9491 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9492 9493 Extra roots can come from periodic cuts, where additional points appear on the boundary 9494 9495 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9496 @*/ 9497 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9498 { 9499 PetscInt l, nleaves, nroots, overlap; 9500 const PetscInt *locals; 9501 const PetscSFNode *remotes; 9502 PetscBool distributed; 9503 MPI_Comm comm; 9504 PetscMPIInt rank; 9505 9506 PetscFunctionBegin; 9507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9508 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9509 else pointSF = dm->sf; 9510 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9511 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9512 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9513 { 9514 PetscMPIInt mpiFlag; 9515 9516 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9517 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9518 } 9519 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9520 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9521 if (!distributed) { 9522 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); 9523 PetscFunctionReturn(PETSC_SUCCESS); 9524 } 9525 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); 9526 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9527 9528 /* Check SF graph is compatible with DMPlex chart */ 9529 { 9530 PetscInt pStart, pEnd, maxLeaf; 9531 9532 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9533 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9534 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9535 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9536 } 9537 9538 /* Check Point SF has no local points referenced */ 9539 for (l = 0; l < nleaves; l++) { 9540 PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%d,%" PetscInt_FMT ")", locals ? locals[l] : l, (PetscMPIInt)remotes[l].rank, remotes[l].index); 9541 } 9542 9543 /* Check there are no cells in interface */ 9544 if (!overlap) { 9545 PetscInt cellHeight, cStart, cEnd; 9546 9547 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9548 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9549 for (l = 0; l < nleaves; ++l) { 9550 const PetscInt point = locals ? locals[l] : l; 9551 9552 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9553 } 9554 } 9555 9556 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9557 { 9558 const PetscInt *rootdegree; 9559 9560 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9561 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9562 for (l = 0; l < nleaves; ++l) { 9563 const PetscInt point = locals ? locals[l] : l; 9564 const PetscInt *cone; 9565 PetscInt coneSize, c, idx; 9566 9567 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9568 PetscCall(DMPlexGetCone(dm, point, &cone)); 9569 for (c = 0; c < coneSize; ++c) { 9570 if (!rootdegree[cone[c]]) { 9571 if (locals) { 9572 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9573 } else { 9574 idx = (cone[c] < nleaves) ? cone[c] : -1; 9575 } 9576 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9577 } 9578 } 9579 } 9580 } 9581 PetscFunctionReturn(PETSC_SUCCESS); 9582 } 9583 9584 /*@ 9585 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9586 9587 Collective 9588 9589 Input Parameter: 9590 . dm - The `DMPLEX` object 9591 9592 Level: developer 9593 9594 Notes: 9595 This is mainly intended for debugging/testing purposes. 9596 9597 Other cell types which are disconnected would be caught by the symmetry and face checks. 9598 9599 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9600 9601 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9602 @*/ 9603 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9604 { 9605 PetscInt pStart, pEnd, vStart, vEnd; 9606 9607 PetscFunctionBegin; 9608 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9609 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9610 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9611 for (PetscInt v = vStart; v < vEnd; ++v) { 9612 PetscInt suppSize; 9613 9614 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9615 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9616 } 9617 PetscFunctionReturn(PETSC_SUCCESS); 9618 } 9619 9620 /*@ 9621 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9622 9623 Input Parameter: 9624 . dm - The `DMPLEX` object 9625 9626 Level: developer 9627 9628 Notes: 9629 This is a useful diagnostic when creating meshes programmatically. 9630 9631 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9632 9633 Currently does not include `DMPlexCheckCellShape()`. 9634 9635 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9636 @*/ 9637 PetscErrorCode DMPlexCheck(DM dm) 9638 { 9639 PetscInt cellHeight; 9640 9641 PetscFunctionBegin; 9642 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9643 PetscCall(DMPlexCheckSymmetry(dm)); 9644 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9645 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9646 PetscCall(DMPlexCheckGeometry(dm)); 9647 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9648 PetscCall(DMPlexCheckInterfaceCones(dm)); 9649 PetscCall(DMPlexCheckOrphanVertices(dm)); 9650 PetscFunctionReturn(PETSC_SUCCESS); 9651 } 9652 9653 typedef struct cell_stats { 9654 PetscReal min, max, sum, squaresum; 9655 PetscInt count; 9656 } cell_stats_t; 9657 9658 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9659 { 9660 PetscInt i, N = *len; 9661 9662 for (i = 0; i < N; i++) { 9663 cell_stats_t *A = (cell_stats_t *)a; 9664 cell_stats_t *B = (cell_stats_t *)b; 9665 9666 B->min = PetscMin(A->min, B->min); 9667 B->max = PetscMax(A->max, B->max); 9668 B->sum += A->sum; 9669 B->squaresum += A->squaresum; 9670 B->count += A->count; 9671 } 9672 } 9673 9674 /*@ 9675 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9676 9677 Collective 9678 9679 Input Parameters: 9680 + dm - The `DMPLEX` object 9681 . output - If true, statistics will be displayed on `stdout` 9682 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9683 9684 Level: developer 9685 9686 Notes: 9687 This is mainly intended for debugging/testing purposes. 9688 9689 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9690 9691 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9692 @*/ 9693 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9694 { 9695 DM dmCoarse; 9696 cell_stats_t stats, globalStats; 9697 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9698 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9699 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9700 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9701 PetscMPIInt rank, size; 9702 9703 PetscFunctionBegin; 9704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9705 stats.min = PETSC_MAX_REAL; 9706 stats.max = PETSC_MIN_REAL; 9707 stats.sum = stats.squaresum = 0.; 9708 stats.count = 0; 9709 9710 PetscCallMPI(MPI_Comm_size(comm, &size)); 9711 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9712 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9713 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9714 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9715 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9716 for (c = cStart; c < cEnd; c++) { 9717 PetscInt i; 9718 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9719 9720 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9721 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9722 for (i = 0; i < PetscSqr(cdim); ++i) { 9723 frobJ += J[i] * J[i]; 9724 frobInvJ += invJ[i] * invJ[i]; 9725 } 9726 cond2 = frobJ * frobInvJ; 9727 cond = PetscSqrtReal(cond2); 9728 9729 stats.min = PetscMin(stats.min, cond); 9730 stats.max = PetscMax(stats.max, cond); 9731 stats.sum += cond; 9732 stats.squaresum += cond2; 9733 stats.count++; 9734 if (output && cond > limit) { 9735 PetscSection coordSection; 9736 Vec coordsLocal; 9737 PetscScalar *coords = NULL; 9738 PetscInt Nv, d, clSize, cl, *closure = NULL; 9739 9740 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9741 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9742 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9743 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9744 for (i = 0; i < Nv / cdim; ++i) { 9745 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9746 for (d = 0; d < cdim; ++d) { 9747 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9748 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9749 } 9750 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9751 } 9752 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9753 for (cl = 0; cl < clSize * 2; cl += 2) { 9754 const PetscInt edge = closure[cl]; 9755 9756 if ((edge >= eStart) && (edge < eEnd)) { 9757 PetscReal len; 9758 9759 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9760 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9761 } 9762 } 9763 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9764 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9765 } 9766 } 9767 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9768 9769 if (size > 1) { 9770 PetscMPIInt blockLengths[2] = {4, 1}; 9771 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9772 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9773 MPI_Op statReduce; 9774 9775 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9776 PetscCallMPI(MPI_Type_commit(&statType)); 9777 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9778 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9779 PetscCallMPI(MPI_Op_free(&statReduce)); 9780 PetscCallMPI(MPI_Type_free(&statType)); 9781 } else { 9782 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9783 } 9784 if (rank == 0) { 9785 count = globalStats.count; 9786 min = globalStats.min; 9787 max = globalStats.max; 9788 mean = globalStats.sum / globalStats.count; 9789 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9790 } 9791 9792 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)); 9793 PetscCall(PetscFree2(J, invJ)); 9794 9795 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9796 if (dmCoarse) { 9797 PetscBool isplex; 9798 9799 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9800 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9801 } 9802 PetscFunctionReturn(PETSC_SUCCESS); 9803 } 9804 9805 /*@ 9806 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9807 orthogonal quality below given tolerance. 9808 9809 Collective 9810 9811 Input Parameters: 9812 + dm - The `DMPLEX` object 9813 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9814 - atol - [0, 1] Absolute tolerance for tagging cells. 9815 9816 Output Parameters: 9817 + OrthQual - `Vec` containing orthogonal quality per cell 9818 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9819 9820 Options Database Keys: 9821 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9822 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9823 9824 Level: intermediate 9825 9826 Notes: 9827 Orthogonal quality is given by the following formula\: 9828 9829 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9830 9831 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 9832 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9833 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9834 calculating the cosine of the angle between these vectors. 9835 9836 Orthogonal quality ranges from 1 (best) to 0 (worst). 9837 9838 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9839 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9840 9841 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9842 9843 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9844 @*/ 9845 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9846 { 9847 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9848 PetscInt *idx; 9849 PetscScalar *oqVals; 9850 const PetscScalar *cellGeomArr, *faceGeomArr; 9851 PetscReal *ci, *fi, *Ai; 9852 MPI_Comm comm; 9853 Vec cellgeom, facegeom; 9854 DM dmFace, dmCell; 9855 IS glob; 9856 ISLocalToGlobalMapping ltog; 9857 PetscViewer vwr; 9858 9859 PetscFunctionBegin; 9860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9861 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9862 PetscAssertPointer(OrthQual, 4); 9863 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9864 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9865 PetscCall(DMGetDimension(dm, &nc)); 9866 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9867 { 9868 DMPlexInterpolatedFlag interpFlag; 9869 9870 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9871 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9872 PetscMPIInt rank; 9873 9874 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9875 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9876 } 9877 } 9878 if (OrthQualLabel) { 9879 PetscAssertPointer(OrthQualLabel, 5); 9880 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9881 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9882 } else { 9883 *OrthQualLabel = NULL; 9884 } 9885 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9886 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9887 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9888 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9889 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9890 PetscCall(VecCreate(comm, OrthQual)); 9891 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9892 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9893 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9894 PetscCall(VecSetUp(*OrthQual)); 9895 PetscCall(ISDestroy(&glob)); 9896 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9897 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9898 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9899 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9900 PetscCall(VecGetDM(cellgeom, &dmCell)); 9901 PetscCall(VecGetDM(facegeom, &dmFace)); 9902 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9903 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9904 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9905 PetscInt cellarr[2], *adj = NULL; 9906 PetscScalar *cArr, *fArr; 9907 PetscReal minvalc = 1.0, minvalf = 1.0; 9908 PetscFVCellGeom *cg; 9909 9910 idx[cellIter] = cell - cStart; 9911 cellarr[0] = cell; 9912 /* Make indexing into cellGeom easier */ 9913 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9914 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9915 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9916 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9917 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9918 PetscInt i; 9919 const PetscInt neigh = adj[cellneigh]; 9920 PetscReal normci = 0, normfi = 0, normai = 0; 9921 PetscFVCellGeom *cgneigh; 9922 PetscFVFaceGeom *fg; 9923 9924 /* Don't count ourselves in the neighbor list */ 9925 if (neigh == cell) continue; 9926 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9927 cellarr[1] = neigh; 9928 { 9929 PetscInt numcovpts; 9930 const PetscInt *covpts; 9931 9932 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9933 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9934 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9935 } 9936 9937 /* Compute c_i, f_i and their norms */ 9938 for (i = 0; i < nc; i++) { 9939 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9940 fi[i] = fg->centroid[i] - cg->centroid[i]; 9941 Ai[i] = fg->normal[i]; 9942 normci += PetscPowReal(ci[i], 2); 9943 normfi += PetscPowReal(fi[i], 2); 9944 normai += PetscPowReal(Ai[i], 2); 9945 } 9946 normci = PetscSqrtReal(normci); 9947 normfi = PetscSqrtReal(normfi); 9948 normai = PetscSqrtReal(normai); 9949 9950 /* Normalize and compute for each face-cell-normal pair */ 9951 for (i = 0; i < nc; i++) { 9952 ci[i] = ci[i] / normci; 9953 fi[i] = fi[i] / normfi; 9954 Ai[i] = Ai[i] / normai; 9955 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9956 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9957 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9958 } 9959 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9960 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9961 } 9962 PetscCall(PetscFree(adj)); 9963 PetscCall(PetscFree2(cArr, fArr)); 9964 /* Defer to cell if they're equal */ 9965 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9966 if (OrthQualLabel) { 9967 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9968 } 9969 } 9970 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9971 PetscCall(VecAssemblyBegin(*OrthQual)); 9972 PetscCall(VecAssemblyEnd(*OrthQual)); 9973 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9974 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9975 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9976 if (OrthQualLabel) { 9977 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9978 } 9979 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9980 PetscCall(PetscViewerDestroy(&vwr)); 9981 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9982 PetscFunctionReturn(PETSC_SUCCESS); 9983 } 9984 9985 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9986 * interpolator construction */ 9987 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9988 { 9989 PetscSection section, newSection, gsection; 9990 PetscSF sf; 9991 PetscBool hasConstraints, ghasConstraints; 9992 9993 PetscFunctionBegin; 9994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9995 PetscAssertPointer(odm, 2); 9996 PetscCall(DMGetLocalSection(dm, §ion)); 9997 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9998 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9999 if (!ghasConstraints) { 10000 PetscCall(PetscObjectReference((PetscObject)dm)); 10001 *odm = dm; 10002 PetscFunctionReturn(PETSC_SUCCESS); 10003 } 10004 PetscCall(DMClone(dm, odm)); 10005 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10006 PetscCall(DMGetLocalSection(*odm, &newSection)); 10007 PetscCall(DMGetPointSF(*odm, &sf)); 10008 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10009 PetscCall(DMSetGlobalSection(*odm, gsection)); 10010 PetscCall(PetscSectionDestroy(&gsection)); 10011 PetscFunctionReturn(PETSC_SUCCESS); 10012 } 10013 10014 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10015 { 10016 DM dmco, dmfo; 10017 Mat interpo; 10018 Vec rscale; 10019 Vec cglobalo, clocal; 10020 Vec fglobal, fglobalo, flocal; 10021 PetscBool regular; 10022 10023 PetscFunctionBegin; 10024 PetscCall(DMGetFullDM(dmc, &dmco)); 10025 PetscCall(DMGetFullDM(dmf, &dmfo)); 10026 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10027 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10028 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10029 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10030 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10031 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10032 PetscCall(VecSet(cglobalo, 0.)); 10033 PetscCall(VecSet(clocal, 0.)); 10034 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10035 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10036 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10037 PetscCall(VecSet(fglobal, 0.)); 10038 PetscCall(VecSet(fglobalo, 0.)); 10039 PetscCall(VecSet(flocal, 0.)); 10040 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10041 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10042 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10043 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10044 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10045 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10046 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10047 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10048 *shift = fglobal; 10049 PetscCall(VecDestroy(&flocal)); 10050 PetscCall(VecDestroy(&fglobalo)); 10051 PetscCall(VecDestroy(&clocal)); 10052 PetscCall(VecDestroy(&cglobalo)); 10053 PetscCall(VecDestroy(&rscale)); 10054 PetscCall(MatDestroy(&interpo)); 10055 PetscCall(DMDestroy(&dmfo)); 10056 PetscCall(DMDestroy(&dmco)); 10057 PetscFunctionReturn(PETSC_SUCCESS); 10058 } 10059 10060 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10061 { 10062 PetscObject shifto; 10063 Vec shift; 10064 10065 PetscFunctionBegin; 10066 if (!interp) { 10067 Vec rscale; 10068 10069 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10070 PetscCall(VecDestroy(&rscale)); 10071 } else { 10072 PetscCall(PetscObjectReference((PetscObject)interp)); 10073 } 10074 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10075 if (!shifto) { 10076 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10077 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10078 shifto = (PetscObject)shift; 10079 PetscCall(VecDestroy(&shift)); 10080 } 10081 shift = (Vec)shifto; 10082 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10083 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10084 PetscCall(MatDestroy(&interp)); 10085 PetscFunctionReturn(PETSC_SUCCESS); 10086 } 10087 10088 /* Pointwise interpolation 10089 Just code FEM for now 10090 u^f = I u^c 10091 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10092 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10093 I_{ij} = psi^f_i phi^c_j 10094 */ 10095 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10096 { 10097 PetscSection gsc, gsf; 10098 PetscInt m, n; 10099 void *ctx; 10100 DM cdm; 10101 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10102 10103 PetscFunctionBegin; 10104 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10105 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10106 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10107 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10108 10109 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10110 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10111 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10112 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10113 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10114 10115 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10116 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10117 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10118 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10119 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10120 if (scaling) { 10121 /* Use naive scaling */ 10122 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10123 } 10124 PetscFunctionReturn(PETSC_SUCCESS); 10125 } 10126 10127 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10128 { 10129 VecScatter ctx; 10130 10131 PetscFunctionBegin; 10132 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10133 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10134 PetscCall(VecScatterDestroy(&ctx)); 10135 PetscFunctionReturn(PETSC_SUCCESS); 10136 } 10137 10138 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[]) 10139 { 10140 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10141 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10142 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10143 } 10144 10145 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10146 { 10147 DM dmc; 10148 PetscDS ds; 10149 Vec ones, locmass; 10150 IS cellIS; 10151 PetscFormKey key; 10152 PetscInt depth; 10153 10154 PetscFunctionBegin; 10155 PetscCall(DMClone(dm, &dmc)); 10156 PetscCall(DMCopyDisc(dm, dmc)); 10157 PetscCall(DMGetDS(dmc, &ds)); 10158 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10159 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10160 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10161 else PetscCall(DMGetLocalVector(dm, &locmass)); 10162 PetscCall(DMGetLocalVector(dm, &ones)); 10163 PetscCall(DMPlexGetDepth(dm, &depth)); 10164 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10165 PetscCall(VecSet(locmass, 0.0)); 10166 PetscCall(VecSet(ones, 1.0)); 10167 key.label = NULL; 10168 key.value = 0; 10169 key.field = 0; 10170 key.part = 0; 10171 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10172 PetscCall(ISDestroy(&cellIS)); 10173 if (mass) { 10174 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10175 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10176 } 10177 PetscCall(DMRestoreLocalVector(dm, &ones)); 10178 if (lmass) *lmass = locmass; 10179 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10180 PetscCall(DMDestroy(&dmc)); 10181 PetscFunctionReturn(PETSC_SUCCESS); 10182 } 10183 10184 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10185 { 10186 PetscSection gsc, gsf; 10187 PetscInt m, n; 10188 void *ctx; 10189 DM cdm; 10190 PetscBool regular; 10191 10192 PetscFunctionBegin; 10193 if (dmFine == dmCoarse) { 10194 DM dmc; 10195 PetscDS ds; 10196 PetscWeakForm wf; 10197 Vec u; 10198 IS cellIS; 10199 PetscFormKey key; 10200 PetscInt depth; 10201 10202 PetscCall(DMClone(dmFine, &dmc)); 10203 PetscCall(DMCopyDisc(dmFine, dmc)); 10204 PetscCall(DMGetDS(dmc, &ds)); 10205 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10206 PetscCall(PetscWeakFormClear(wf)); 10207 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10208 PetscCall(DMCreateMatrix(dmc, mass)); 10209 PetscCall(DMGetLocalVector(dmc, &u)); 10210 PetscCall(DMPlexGetDepth(dmc, &depth)); 10211 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10212 PetscCall(MatZeroEntries(*mass)); 10213 key.label = NULL; 10214 key.value = 0; 10215 key.field = 0; 10216 key.part = 0; 10217 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10218 PetscCall(ISDestroy(&cellIS)); 10219 PetscCall(DMRestoreLocalVector(dmc, &u)); 10220 PetscCall(DMDestroy(&dmc)); 10221 } else { 10222 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10223 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10224 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10225 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10226 10227 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10228 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10229 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10230 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10231 10232 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10233 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10234 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10235 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10236 } 10237 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10238 PetscFunctionReturn(PETSC_SUCCESS); 10239 } 10240 10241 /*@ 10242 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10243 10244 Input Parameter: 10245 . dm - The `DMPLEX` object 10246 10247 Output Parameter: 10248 . regular - The flag 10249 10250 Level: intermediate 10251 10252 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10253 @*/ 10254 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10255 { 10256 PetscFunctionBegin; 10257 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10258 PetscAssertPointer(regular, 2); 10259 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10260 PetscFunctionReturn(PETSC_SUCCESS); 10261 } 10262 10263 /*@ 10264 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10265 10266 Input Parameters: 10267 + dm - The `DMPLEX` object 10268 - regular - The flag 10269 10270 Level: intermediate 10271 10272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10273 @*/ 10274 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10275 { 10276 PetscFunctionBegin; 10277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10278 ((DM_Plex *)dm->data)->regularRefinement = regular; 10279 PetscFunctionReturn(PETSC_SUCCESS); 10280 } 10281 10282 /*@ 10283 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10284 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10285 10286 Not Collective 10287 10288 Input Parameter: 10289 . dm - The `DMPLEX` object 10290 10291 Output Parameters: 10292 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10293 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10294 10295 Level: intermediate 10296 10297 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10298 @*/ 10299 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10300 { 10301 DM_Plex *plex = (DM_Plex *)dm->data; 10302 10303 PetscFunctionBegin; 10304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10305 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10306 if (anchorSection) *anchorSection = plex->anchorSection; 10307 if (anchorIS) *anchorIS = plex->anchorIS; 10308 PetscFunctionReturn(PETSC_SUCCESS); 10309 } 10310 10311 /*@ 10312 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10313 10314 Collective 10315 10316 Input Parameters: 10317 + dm - The `DMPLEX` object 10318 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10319 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10320 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10321 10322 Level: intermediate 10323 10324 Notes: 10325 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10326 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10327 combination of other points' degrees of freedom. 10328 10329 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10330 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10331 10332 The reference counts of `anchorSection` and `anchorIS` are incremented. 10333 10334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10335 @*/ 10336 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10337 { 10338 DM_Plex *plex = (DM_Plex *)dm->data; 10339 PetscMPIInt result; 10340 10341 PetscFunctionBegin; 10342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10343 if (anchorSection) { 10344 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10345 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10346 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10347 } 10348 if (anchorIS) { 10349 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10350 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10351 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10352 } 10353 10354 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10355 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10356 plex->anchorSection = anchorSection; 10357 10358 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10359 PetscCall(ISDestroy(&plex->anchorIS)); 10360 plex->anchorIS = anchorIS; 10361 10362 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10363 PetscInt size, a, pStart, pEnd; 10364 const PetscInt *anchors; 10365 10366 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10367 PetscCall(ISGetLocalSize(anchorIS, &size)); 10368 PetscCall(ISGetIndices(anchorIS, &anchors)); 10369 for (a = 0; a < size; a++) { 10370 PetscInt p; 10371 10372 p = anchors[a]; 10373 if (p >= pStart && p < pEnd) { 10374 PetscInt dof; 10375 10376 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10377 if (dof) { 10378 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10379 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10380 } 10381 } 10382 } 10383 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10384 } 10385 /* reset the generic constraints */ 10386 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10387 PetscFunctionReturn(PETSC_SUCCESS); 10388 } 10389 10390 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10391 { 10392 PetscSection anchorSection; 10393 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10394 10395 PetscFunctionBegin; 10396 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10397 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10398 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10399 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10400 if (numFields) { 10401 PetscInt f; 10402 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10403 10404 for (f = 0; f < numFields; f++) { 10405 PetscInt numComp; 10406 10407 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10408 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10409 } 10410 } 10411 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10412 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10413 pStart = PetscMax(pStart, sStart); 10414 pEnd = PetscMin(pEnd, sEnd); 10415 pEnd = PetscMax(pStart, pEnd); 10416 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10417 for (p = pStart; p < pEnd; p++) { 10418 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10419 if (dof) { 10420 PetscCall(PetscSectionGetDof(section, p, &dof)); 10421 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10422 for (f = 0; f < numFields; f++) { 10423 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10424 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10425 } 10426 } 10427 } 10428 PetscCall(PetscSectionSetUp(*cSec)); 10429 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10430 PetscFunctionReturn(PETSC_SUCCESS); 10431 } 10432 10433 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10434 { 10435 PetscSection aSec; 10436 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10437 const PetscInt *anchors; 10438 PetscInt numFields, f; 10439 IS aIS; 10440 MatType mtype; 10441 PetscBool iscuda, iskokkos; 10442 10443 PetscFunctionBegin; 10444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10445 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10446 PetscCall(PetscSectionGetStorageSize(section, &n)); 10447 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10448 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10449 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10450 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10451 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10452 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10453 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10454 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10455 else mtype = MATSEQAIJ; 10456 PetscCall(MatSetType(*cMat, mtype)); 10457 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10458 PetscCall(ISGetIndices(aIS, &anchors)); 10459 /* cSec will be a subset of aSec and section */ 10460 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10461 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10462 PetscCall(PetscMalloc1(m + 1, &i)); 10463 i[0] = 0; 10464 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10465 for (p = pStart; p < pEnd; p++) { 10466 PetscInt rDof, rOff, r; 10467 10468 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10469 if (!rDof) continue; 10470 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10471 if (numFields) { 10472 for (f = 0; f < numFields; f++) { 10473 annz = 0; 10474 for (r = 0; r < rDof; r++) { 10475 a = anchors[rOff + r]; 10476 if (a < sStart || a >= sEnd) continue; 10477 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10478 annz += aDof; 10479 } 10480 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10481 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10482 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10483 } 10484 } else { 10485 annz = 0; 10486 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10487 for (q = 0; q < dof; q++) { 10488 a = anchors[rOff + q]; 10489 if (a < sStart || a >= sEnd) continue; 10490 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10491 annz += aDof; 10492 } 10493 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10494 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10495 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10496 } 10497 } 10498 nnz = i[m]; 10499 PetscCall(PetscMalloc1(nnz, &j)); 10500 offset = 0; 10501 for (p = pStart; p < pEnd; p++) { 10502 if (numFields) { 10503 for (f = 0; f < numFields; f++) { 10504 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10505 for (q = 0; q < dof; q++) { 10506 PetscInt rDof, rOff, r; 10507 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10508 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10509 for (r = 0; r < rDof; r++) { 10510 PetscInt s; 10511 10512 a = anchors[rOff + r]; 10513 if (a < sStart || a >= sEnd) continue; 10514 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10515 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10516 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10517 } 10518 } 10519 } 10520 } else { 10521 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10522 for (q = 0; q < dof; q++) { 10523 PetscInt rDof, rOff, r; 10524 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10525 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10526 for (r = 0; r < rDof; r++) { 10527 PetscInt s; 10528 10529 a = anchors[rOff + r]; 10530 if (a < sStart || a >= sEnd) continue; 10531 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10532 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10533 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10534 } 10535 } 10536 } 10537 } 10538 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10539 PetscCall(PetscFree(i)); 10540 PetscCall(PetscFree(j)); 10541 PetscCall(ISRestoreIndices(aIS, &anchors)); 10542 PetscFunctionReturn(PETSC_SUCCESS); 10543 } 10544 10545 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10546 { 10547 DM_Plex *plex = (DM_Plex *)dm->data; 10548 PetscSection anchorSection, section, cSec; 10549 Mat cMat; 10550 10551 PetscFunctionBegin; 10552 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10553 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10554 if (anchorSection) { 10555 PetscInt Nf; 10556 10557 PetscCall(DMGetLocalSection(dm, §ion)); 10558 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10559 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10560 PetscCall(DMGetNumFields(dm, &Nf)); 10561 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10562 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10563 PetscCall(PetscSectionDestroy(&cSec)); 10564 PetscCall(MatDestroy(&cMat)); 10565 } 10566 PetscFunctionReturn(PETSC_SUCCESS); 10567 } 10568 10569 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10570 { 10571 IS subis; 10572 PetscSection section, subsection; 10573 10574 PetscFunctionBegin; 10575 PetscCall(DMGetLocalSection(dm, §ion)); 10576 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10577 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10578 /* Create subdomain */ 10579 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10580 /* Create submodel */ 10581 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10582 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10583 PetscCall(DMSetLocalSection(*subdm, subsection)); 10584 PetscCall(PetscSectionDestroy(&subsection)); 10585 PetscCall(DMCopyDisc(dm, *subdm)); 10586 /* Create map from submodel to global model */ 10587 if (is) { 10588 PetscSection sectionGlobal, subsectionGlobal; 10589 IS spIS; 10590 const PetscInt *spmap; 10591 PetscInt *subIndices; 10592 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10593 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10594 10595 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10596 PetscCall(ISGetIndices(spIS, &spmap)); 10597 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10598 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10599 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10600 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10601 for (p = pStart; p < pEnd; ++p) { 10602 PetscInt gdof, pSubSize = 0; 10603 10604 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10605 if (gdof > 0) { 10606 for (f = 0; f < Nf; ++f) { 10607 PetscInt fdof, fcdof; 10608 10609 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10610 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10611 pSubSize += fdof - fcdof; 10612 } 10613 subSize += pSubSize; 10614 if (pSubSize) { 10615 if (bs < 0) { 10616 bs = pSubSize; 10617 } else if (bs != pSubSize) { 10618 /* Layout does not admit a pointwise block size */ 10619 bs = 1; 10620 } 10621 } 10622 } 10623 } 10624 /* Must have same blocksize on all procs (some might have no points) */ 10625 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10626 bsLocal[1] = bs; 10627 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10628 if (bsMinMax[0] != bsMinMax[1]) { 10629 bs = 1; 10630 } else { 10631 bs = bsMinMax[0]; 10632 } 10633 PetscCall(PetscMalloc1(subSize, &subIndices)); 10634 for (p = pStart; p < pEnd; ++p) { 10635 PetscInt gdof, goff; 10636 10637 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10638 if (gdof > 0) { 10639 const PetscInt point = spmap[p]; 10640 10641 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10642 for (f = 0; f < Nf; ++f) { 10643 PetscInt fdof, fcdof, fc, f2, poff = 0; 10644 10645 /* Can get rid of this loop by storing field information in the global section */ 10646 for (f2 = 0; f2 < f; ++f2) { 10647 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10648 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10649 poff += fdof - fcdof; 10650 } 10651 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10652 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10653 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10654 } 10655 } 10656 } 10657 PetscCall(ISRestoreIndices(spIS, &spmap)); 10658 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10659 if (bs > 1) { 10660 /* We need to check that the block size does not come from non-contiguous fields */ 10661 PetscInt i, j, set = 1; 10662 for (i = 0; i < subSize; i += bs) { 10663 for (j = 0; j < bs; ++j) { 10664 if (subIndices[i + j] != subIndices[i] + j) { 10665 set = 0; 10666 break; 10667 } 10668 } 10669 } 10670 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10671 } 10672 /* Attach nullspace */ 10673 for (f = 0; f < Nf; ++f) { 10674 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10675 if ((*subdm)->nullspaceConstructors[f]) break; 10676 } 10677 if (f < Nf) { 10678 MatNullSpace nullSpace; 10679 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10680 10681 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10682 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10683 } 10684 } 10685 PetscFunctionReturn(PETSC_SUCCESS); 10686 } 10687 10688 /*@ 10689 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10690 10691 Input Parameters: 10692 + dm - The `DM` 10693 - dummy - unused argument 10694 10695 Options Database Key: 10696 . -dm_plex_monitor_throughput - Activate the monitor 10697 10698 Level: developer 10699 10700 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10701 @*/ 10702 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10703 { 10704 PetscLogHandler default_handler; 10705 10706 PetscFunctionBegin; 10707 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10708 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10709 if (default_handler) { 10710 PetscLogEvent event; 10711 PetscEventPerfInfo eventInfo; 10712 PetscReal cellRate, flopRate; 10713 PetscInt cStart, cEnd, Nf, N; 10714 const char *name; 10715 10716 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10717 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10718 PetscCall(DMGetNumFields(dm, &Nf)); 10719 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10720 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10721 N = (cEnd - cStart) * Nf * eventInfo.count; 10722 flopRate = eventInfo.flops / eventInfo.time; 10723 cellRate = N / eventInfo.time; 10724 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))); 10725 } else { 10726 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."); 10727 } 10728 PetscFunctionReturn(PETSC_SUCCESS); 10729 } 10730