1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscBool found = PETSC_FALSE; 89 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 90 91 PetscFunctionBegin; 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 94 PetscCall(ISGetLocalSize(valueIS, &Nct)); 95 PetscCall(ISGetIndices(valueIS, &ctypes)); 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 found = PETSC_TRUE; 114 } 115 if (!Nct || !found) cS = cE = 0; 116 PetscCall(ISDestroy(&valueIS)); 117 // Reset label for fast lookup 118 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 119 if (cStart) *cStart = cS; 120 if (cEnd) *cEnd = cE; 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 125 { 126 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 127 PetscInt *sStart, *sEnd; 128 PetscViewerVTKFieldType *ft; 129 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 130 DMLabel depthLabel, ctLabel; 131 132 PetscFunctionBegin; 133 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 134 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 135 PetscCall(DMGetCoordinateDim(dm, &cdim)); 136 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 137 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 138 if (field >= 0) { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 140 } else { 141 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 142 } 143 144 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 145 PetscCall(DMPlexGetDepth(dm, &depth)); 146 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 147 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 148 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 149 const DMPolytopeType ict = (DMPolytopeType)c; 150 PetscInt dep; 151 152 if (ict == DM_POLYTOPE_FV_GHOST) continue; 153 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 154 if (pStart >= 0) { 155 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 156 if (dep != depth - cellHeight) continue; 157 } 158 if (field >= 0) { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 160 } else { 161 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 162 } 163 } 164 165 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 166 *types = 0; 167 168 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 169 if (globalvcdof[c]) ++(*types); 170 } 171 172 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 173 t = 0; 174 if (globalvcdof[DM_NUM_POLYTOPES]) { 175 sStart[t] = vStart; 176 sEnd[t] = vEnd; 177 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 178 ++t; 179 } 180 181 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 182 if (globalvcdof[c]) { 183 const DMPolytopeType ict = (DMPolytopeType)c; 184 185 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 186 sStart[t] = cStart; 187 sEnd[t] = cEnd; 188 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 189 ++t; 190 } 191 } 192 193 if (!*types) { 194 if (field >= 0) { 195 const char *fieldname; 196 197 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 199 } else { 200 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 201 } 202 } 203 204 *ssStart = sStart; 205 *ssEnd = sEnd; 206 *sft = ft; 207 PetscFunctionReturn(PETSC_SUCCESS); 208 } 209 210 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 211 { 212 PetscFunctionBegin; 213 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 214 PetscFunctionReturn(PETSC_SUCCESS); 215 } 216 217 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 218 { 219 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 220 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 221 222 PetscFunctionBegin; 223 *ft = PETSC_VTK_INVALID; 224 PetscCall(DMGetCoordinateDim(dm, &cdim)); 225 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 226 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 227 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 228 if (field >= 0) { 229 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 230 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 231 } else { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 234 } 235 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 236 if (globalvcdof[0]) { 237 *sStart = vStart; 238 *sEnd = vEnd; 239 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 240 else *ft = PETSC_VTK_POINT_FIELD; 241 } else if (globalvcdof[1]) { 242 *sStart = cStart; 243 *sEnd = cEnd; 244 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 245 else *ft = PETSC_VTK_CELL_FIELD; 246 } else { 247 if (field >= 0) { 248 const char *fieldname; 249 250 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 252 } else { 253 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 254 } 255 } 256 PetscFunctionReturn(PETSC_SUCCESS); 257 } 258 259 /*@ 260 DMPlexVecView1D - Plot many 1D solutions on the same line graph 261 262 Collective 263 264 Input Parameters: 265 + dm - The `DMPLEX` object 266 . n - The number of vectors 267 . u - The array of local vectors 268 - viewer - The `PetscViewer` 269 270 Level: advanced 271 272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 273 @*/ 274 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 275 { 276 PetscDS ds; 277 PetscDraw draw = NULL; 278 PetscDrawLG lg; 279 Vec coordinates; 280 const PetscScalar *coords, **sol; 281 PetscReal *vals; 282 PetscInt *Nc; 283 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 284 char **names; 285 286 PetscFunctionBegin; 287 PetscCall(DMGetDS(dm, &ds)); 288 PetscCall(PetscDSGetNumFields(ds, &Nf)); 289 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 290 PetscCall(PetscDSGetComponents(ds, &Nc)); 291 292 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 293 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 294 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 295 296 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 297 for (i = 0, l = 0; i < n; ++i) { 298 const char *vname; 299 300 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 301 for (f = 0; f < Nf; ++f) { 302 PetscObject disc; 303 const char *fname; 304 char tmpname[PETSC_MAX_PATH_LEN]; 305 306 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 307 /* TODO Create names for components */ 308 for (c = 0; c < Nc[f]; ++c, ++l) { 309 PetscCall(PetscObjectGetName(disc, &fname)); 310 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 312 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 313 PetscCall(PetscStrallocpy(tmpname, &names[l])); 314 } 315 } 316 } 317 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 318 /* Just add P_1 support for now */ 319 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 320 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 321 PetscCall(VecGetArrayRead(coordinates, &coords)); 322 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 323 for (v = vStart; v < vEnd; ++v) { 324 PetscScalar *x, *svals; 325 326 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 327 for (i = 0; i < n; ++i) { 328 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 329 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 330 } 331 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 332 } 333 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 334 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 335 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 336 PetscCall(PetscFree3(sol, names, vals)); 337 338 PetscCall(PetscDrawLGDraw(lg)); 339 PetscCall(PetscDrawLGDestroy(&lg)); 340 PetscFunctionReturn(PETSC_SUCCESS); 341 } 342 343 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 344 { 345 DM dm; 346 347 PetscFunctionBegin; 348 PetscCall(VecGetDM(u, &dm)); 349 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 350 PetscFunctionReturn(PETSC_SUCCESS); 351 } 352 353 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 354 { 355 DM dm; 356 PetscSection s; 357 PetscDraw draw, popup; 358 DM cdm; 359 PetscSection coordSection; 360 Vec coordinates; 361 const PetscScalar *array; 362 PetscReal lbound[3], ubound[3]; 363 PetscReal vbound[2], time; 364 PetscBool flg; 365 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 366 const char *name; 367 char title[PETSC_MAX_PATH_LEN]; 368 369 PetscFunctionBegin; 370 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 371 PetscCall(VecGetDM(v, &dm)); 372 PetscCall(DMGetCoordinateDim(dm, &dim)); 373 PetscCall(DMGetLocalSection(dm, &s)); 374 PetscCall(PetscSectionGetNumFields(s, &Nf)); 375 PetscCall(DMGetCoarsenLevel(dm, &level)); 376 PetscCall(DMGetCoordinateDM(dm, &cdm)); 377 PetscCall(DMGetLocalSection(cdm, &coordSection)); 378 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 379 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 380 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 381 382 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 383 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 384 385 PetscCall(VecGetLocalSize(coordinates, &N)); 386 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 387 PetscCall(PetscDrawClear(draw)); 388 389 /* Could implement something like DMDASelectFields() */ 390 for (f = 0; f < Nf; ++f) { 391 DM fdm = dm; 392 Vec fv = v; 393 IS fis; 394 char prefix[PETSC_MAX_PATH_LEN]; 395 const char *fname; 396 397 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 398 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 399 400 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 401 else prefix[0] = '\0'; 402 if (Nf > 1) { 403 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 404 PetscCall(VecGetSubVector(v, fis, &fv)); 405 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 406 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 407 } 408 for (comp = 0; comp < Nc; ++comp, ++w) { 409 PetscInt nmax = 2; 410 411 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 412 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 413 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 414 PetscCall(PetscDrawSetTitle(draw, title)); 415 416 /* TODO Get max and min only for this component */ 417 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 418 if (!flg) { 419 PetscCall(VecMin(fv, NULL, &vbound[0])); 420 PetscCall(VecMax(fv, NULL, &vbound[1])); 421 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 422 } 423 424 PetscCall(PetscDrawGetPopup(draw, &popup)); 425 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 426 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 427 PetscCall(VecGetArrayRead(fv, &array)); 428 for (c = cStart; c < cEnd; ++c) { 429 DMPolytopeType ct; 430 PetscScalar *coords = NULL, *a = NULL; 431 const PetscScalar *coords_arr; 432 PetscBool isDG; 433 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 434 435 PetscCall(DMPlexGetCellType(dm, c, &ct)); 436 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 437 if (a) { 438 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 439 color[1] = color[2] = color[3] = color[0]; 440 } else { 441 PetscScalar *vals = NULL; 442 PetscInt numVals, va; 443 444 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 445 if (!numVals) { 446 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 447 continue; 448 } 449 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); 450 switch (numVals / Nc) { 451 case 1: /* P1 Clamped Segment Prism */ 452 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 453 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]); 454 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 455 break; 456 case 3: /* P1 Triangle */ 457 case 4: /* P1 Quadrangle */ 458 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]); 459 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 460 break; 461 case 6: /* P2 Triangle */ 462 case 8: /* P2 Quadrangle */ 463 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]); 464 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 465 break; 466 default: 467 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 468 } 469 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 470 } 471 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 472 switch (numCoords) { 473 case 6: 474 case 12: /* Localized triangle */ 475 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])); 476 break; 477 case 8: 478 case 16: /* Localized quadrilateral */ 479 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 480 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 481 } else { 482 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])); 483 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])); 484 } 485 break; 486 default: 487 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 488 } 489 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 490 } 491 PetscCall(VecRestoreArrayRead(fv, &array)); 492 PetscCall(PetscDrawFlush(draw)); 493 PetscCall(PetscDrawPause(draw)); 494 PetscCall(PetscDrawSave(draw)); 495 } 496 if (Nf > 1) { 497 PetscCall(VecRestoreSubVector(v, fis, &fv)); 498 PetscCall(ISDestroy(&fis)); 499 PetscCall(DMDestroy(&fdm)); 500 } 501 } 502 PetscFunctionReturn(PETSC_SUCCESS); 503 } 504 505 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 506 { 507 DM dm; 508 PetscDraw draw; 509 PetscInt dim; 510 PetscBool isnull; 511 512 PetscFunctionBegin; 513 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 514 PetscCall(PetscDrawIsNull(draw, &isnull)); 515 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 516 517 PetscCall(VecGetDM(v, &dm)); 518 PetscCall(DMGetCoordinateDim(dm, &dim)); 519 switch (dim) { 520 case 1: 521 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 522 break; 523 case 2: 524 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 525 break; 526 default: 527 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 528 } 529 PetscFunctionReturn(PETSC_SUCCESS); 530 } 531 532 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 533 { 534 DM dm; 535 Vec locv; 536 const char *name; 537 PetscSection section; 538 PetscInt pStart, pEnd; 539 PetscInt numFields; 540 PetscViewerVTKFieldType ft; 541 542 PetscFunctionBegin; 543 PetscCall(VecGetDM(v, &dm)); 544 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 545 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 546 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 547 PetscCall(VecCopy(v, locv)); 548 PetscCall(DMGetLocalSection(dm, §ion)); 549 PetscCall(PetscSectionGetNumFields(section, &numFields)); 550 if (!numFields) { 551 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 552 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 553 } else { 554 PetscInt f; 555 556 for (f = 0; f < numFields; f++) { 557 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 558 if (ft == PETSC_VTK_INVALID) continue; 559 PetscCall(PetscObjectReference((PetscObject)locv)); 560 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 561 } 562 PetscCall(VecDestroy(&locv)); 563 } 564 PetscFunctionReturn(PETSC_SUCCESS); 565 } 566 567 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 568 { 569 DM dm; 570 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 571 572 PetscFunctionBegin; 573 PetscCall(VecGetDM(v, &dm)); 574 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 575 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 576 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 577 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 578 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 579 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 580 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 581 PetscInt i, numFields; 582 PetscObject fe; 583 PetscBool fem = PETSC_FALSE; 584 Vec locv = v; 585 const char *name; 586 PetscInt step; 587 PetscReal time; 588 589 PetscCall(DMGetNumFields(dm, &numFields)); 590 for (i = 0; i < numFields; i++) { 591 PetscCall(DMGetField(dm, i, NULL, &fe)); 592 if (fe->classid == PETSCFE_CLASSID) { 593 fem = PETSC_TRUE; 594 break; 595 } 596 } 597 if (fem) { 598 PetscObject isZero; 599 600 PetscCall(DMGetLocalVector(dm, &locv)); 601 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 602 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 603 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 604 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 605 PetscCall(VecCopy(v, locv)); 606 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 607 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 608 } 609 if (isvtk) { 610 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 611 } else if (ishdf5) { 612 #if defined(PETSC_HAVE_HDF5) 613 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 614 #else 615 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 616 #endif 617 } else if (isdraw) { 618 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 619 } else if (isglvis) { 620 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 621 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 622 PetscCall(VecView_GLVis(locv, viewer)); 623 } else if (iscgns) { 624 #if defined(PETSC_HAVE_CGNS) 625 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 626 #else 627 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 628 #endif 629 } 630 if (fem) { 631 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 632 PetscCall(DMRestoreLocalVector(dm, &locv)); 633 } 634 } else { 635 PetscBool isseq; 636 637 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 638 if (isseq) PetscCall(VecView_Seq(v, viewer)); 639 else PetscCall(VecView_MPI(v, viewer)); 640 } 641 PetscFunctionReturn(PETSC_SUCCESS); 642 } 643 644 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 645 { 646 DM dm; 647 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 648 649 PetscFunctionBegin; 650 PetscCall(VecGetDM(v, &dm)); 651 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 652 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 653 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 654 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 655 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 657 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 658 if (isvtk || isdraw || isglvis || iscgns) { 659 Vec locv; 660 PetscObject isZero; 661 const char *name; 662 663 PetscCall(DMGetLocalVector(dm, &locv)); 664 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 665 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 666 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 667 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 668 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 669 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 670 PetscCall(VecView_Plex_Local(locv, viewer)); 671 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 672 PetscCall(DMRestoreLocalVector(dm, &locv)); 673 /* Call flush for proper logging of VecView timings */ 674 if (isvtk) PetscCall(PetscViewerFlush(viewer)); 675 } else if (ishdf5) { 676 #if defined(PETSC_HAVE_HDF5) 677 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 678 #else 679 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 680 #endif 681 } else if (isexodusii) { 682 #if defined(PETSC_HAVE_EXODUSII) 683 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 684 #else 685 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 686 #endif 687 } else { 688 PetscBool isseq; 689 690 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 691 if (isseq) PetscCall(VecView_Seq(v, viewer)); 692 else PetscCall(VecView_MPI(v, viewer)); 693 } 694 PetscFunctionReturn(PETSC_SUCCESS); 695 } 696 697 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 698 { 699 DM dm; 700 MPI_Comm comm; 701 PetscViewerFormat format; 702 Vec v; 703 PetscBool isvtk, ishdf5; 704 705 PetscFunctionBegin; 706 PetscCall(VecGetDM(originalv, &dm)); 707 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 708 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 709 PetscCall(PetscViewerGetFormat(viewer, &format)); 710 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 711 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 712 if (format == PETSC_VIEWER_NATIVE) { 713 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 714 /* this need a better fix */ 715 if (dm->useNatural) { 716 if (dm->sfNatural) { 717 const char *vecname; 718 PetscInt n, nroots; 719 720 PetscCall(VecGetLocalSize(originalv, &n)); 721 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 722 if (n == nroots) { 723 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 724 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 725 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 726 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 727 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 728 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 729 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 730 } else v = originalv; 731 } else v = originalv; 732 733 if (ishdf5) { 734 #if defined(PETSC_HAVE_HDF5) 735 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 736 #else 737 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 738 #endif 739 } else if (isvtk) { 740 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 741 } else { 742 PetscBool isseq; 743 744 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 745 if (isseq) PetscCall(VecView_Seq(v, viewer)); 746 else PetscCall(VecView_MPI(v, viewer)); 747 } 748 if (v != originalv) PetscCall(VecDestroy(&v)); 749 PetscFunctionReturn(PETSC_SUCCESS); 750 } 751 752 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 753 { 754 DM dm; 755 PetscBool ishdf5; 756 757 PetscFunctionBegin; 758 PetscCall(VecGetDM(v, &dm)); 759 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 760 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 761 if (ishdf5) { 762 DM dmBC; 763 Vec gv; 764 const char *name; 765 766 PetscCall(DMGetOutputDM(dm, &dmBC)); 767 PetscCall(DMGetGlobalVector(dmBC, &gv)); 768 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 769 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 770 PetscCall(VecLoad_Default(gv, viewer)); 771 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 772 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 773 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 774 } else PetscCall(VecLoad_Default(v, viewer)); 775 PetscFunctionReturn(PETSC_SUCCESS); 776 } 777 778 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 779 { 780 DM dm; 781 PetscBool ishdf5, isexodusii; 782 783 PetscFunctionBegin; 784 PetscCall(VecGetDM(v, &dm)); 785 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 786 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 787 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 788 if (ishdf5) { 789 #if defined(PETSC_HAVE_HDF5) 790 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 791 #else 792 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 793 #endif 794 } else if (isexodusii) { 795 #if defined(PETSC_HAVE_EXODUSII) 796 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 797 #else 798 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 799 #endif 800 } else PetscCall(VecLoad_Default(v, viewer)); 801 PetscFunctionReturn(PETSC_SUCCESS); 802 } 803 804 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 805 { 806 DM dm; 807 PetscViewerFormat format; 808 PetscBool ishdf5; 809 810 PetscFunctionBegin; 811 PetscCall(VecGetDM(originalv, &dm)); 812 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 813 PetscCall(PetscViewerGetFormat(viewer, &format)); 814 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 815 if (format == PETSC_VIEWER_NATIVE) { 816 if (dm->useNatural) { 817 if (dm->sfNatural) { 818 if (ishdf5) { 819 #if defined(PETSC_HAVE_HDF5) 820 Vec v; 821 const char *vecname; 822 823 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 824 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 825 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 826 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 827 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 828 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 829 PetscCall(VecDestroy(&v)); 830 #else 831 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 832 #endif 833 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 834 } 835 } else PetscCall(VecLoad_Default(originalv, viewer)); 836 } 837 PetscFunctionReturn(PETSC_SUCCESS); 838 } 839 840 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 841 { 842 PetscSection coordSection; 843 Vec coordinates; 844 DMLabel depthLabel, celltypeLabel; 845 const char *name[4]; 846 const PetscScalar *a; 847 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 848 849 PetscFunctionBegin; 850 PetscCall(DMGetDimension(dm, &dim)); 851 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 852 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 853 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 854 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 855 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 856 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 857 PetscCall(VecGetArrayRead(coordinates, &a)); 858 name[0] = "vertex"; 859 name[1] = "edge"; 860 name[dim - 1] = "face"; 861 name[dim] = "cell"; 862 for (c = cStart; c < cEnd; ++c) { 863 PetscInt *closure = NULL; 864 PetscInt closureSize, cl, ct; 865 866 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 867 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 868 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 869 PetscCall(PetscViewerASCIIPushTab(viewer)); 870 for (cl = 0; cl < closureSize * 2; cl += 2) { 871 PetscInt point = closure[cl], depth, dof, off, d, p; 872 873 if ((point < pStart) || (point >= pEnd)) continue; 874 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 875 if (!dof) continue; 876 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 877 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 878 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 879 for (p = 0; p < dof / dim; ++p) { 880 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 881 for (d = 0; d < dim; ++d) { 882 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 883 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 884 } 885 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 886 } 887 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 888 } 889 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 890 PetscCall(PetscViewerASCIIPopTab(viewer)); 891 } 892 PetscCall(VecRestoreArrayRead(coordinates, &a)); 893 PetscFunctionReturn(PETSC_SUCCESS); 894 } 895 896 typedef enum { 897 CS_CARTESIAN, 898 CS_POLAR, 899 CS_CYLINDRICAL, 900 CS_SPHERICAL 901 } CoordSystem; 902 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 903 904 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 905 { 906 PetscInt i; 907 908 PetscFunctionBegin; 909 if (dim > 3) { 910 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 911 } else { 912 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 913 914 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 915 switch (cs) { 916 case CS_CARTESIAN: 917 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 918 break; 919 case CS_POLAR: 920 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 921 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 922 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 923 break; 924 case CS_CYLINDRICAL: 925 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 926 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 927 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 928 trcoords[2] = coords[2]; 929 break; 930 case CS_SPHERICAL: 931 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 932 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 933 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 934 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 935 break; 936 } 937 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 938 } 939 PetscFunctionReturn(PETSC_SUCCESS); 940 } 941 942 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 943 { 944 DM_Plex *mesh = (DM_Plex *)dm->data; 945 DM cdm, cdmCell; 946 PetscSection coordSection, coordSectionCell; 947 Vec coordinates, coordinatesCell; 948 PetscViewerFormat format; 949 950 PetscFunctionBegin; 951 PetscCall(PetscViewerGetFormat(viewer, &format)); 952 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 953 const char *name; 954 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 955 PetscInt pStart, pEnd, p, numLabels, l; 956 PetscMPIInt rank, size; 957 958 PetscCall(DMGetCoordinateDM(dm, &cdm)); 959 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 960 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 961 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 962 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 963 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 964 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 965 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 966 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 967 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 968 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 969 PetscCall(DMGetDimension(dm, &dim)); 970 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 971 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 972 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 973 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 974 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 975 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 976 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 977 for (p = pStart; p < pEnd; ++p) { 978 PetscInt dof, off, s; 979 980 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 981 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 982 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 983 } 984 PetscCall(PetscViewerFlush(viewer)); 985 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 986 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 987 for (p = pStart; p < pEnd; ++p) { 988 PetscInt dof, off, c; 989 990 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 991 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 992 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])); 993 } 994 PetscCall(PetscViewerFlush(viewer)); 995 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 996 if (coordSection && coordinates) { 997 CoordSystem cs = CS_CARTESIAN; 998 const PetscScalar *array, *arrayCell = NULL; 999 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 1000 PetscMPIInt rank; 1001 const char *name; 1002 1003 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1004 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1005 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1006 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1007 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1008 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1009 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1010 pStart = PetscMin(pvStart, pcStart); 1011 pEnd = PetscMax(pvEnd, pcEnd); 1012 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1013 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1014 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1015 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1016 1017 PetscCall(VecGetArrayRead(coordinates, &array)); 1018 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1019 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1020 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1021 for (p = pStart; p < pEnd; ++p) { 1022 PetscInt dof, off; 1023 1024 if (p >= pvStart && p < pvEnd) { 1025 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1026 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1027 if (dof) { 1028 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1029 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1030 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1031 } 1032 } 1033 if (cdmCell && p >= pcStart && p < pcEnd) { 1034 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1035 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1036 if (dof) { 1037 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1038 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1039 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1040 } 1041 } 1042 } 1043 PetscCall(PetscViewerFlush(viewer)); 1044 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1045 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1046 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1047 } 1048 PetscCall(DMGetNumLabels(dm, &numLabels)); 1049 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1050 for (l = 0; l < numLabels; ++l) { 1051 DMLabel label; 1052 PetscBool isdepth; 1053 const char *name; 1054 1055 PetscCall(DMGetLabelName(dm, l, &name)); 1056 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1057 if (isdepth) continue; 1058 PetscCall(DMGetLabel(dm, name, &label)); 1059 PetscCall(DMLabelView(label, viewer)); 1060 } 1061 if (size > 1) { 1062 PetscSF sf; 1063 1064 PetscCall(DMGetPointSF(dm, &sf)); 1065 PetscCall(PetscSFView(sf, viewer)); 1066 } 1067 if (mesh->periodic.face_sfs) 1068 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1069 PetscCall(PetscViewerFlush(viewer)); 1070 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1071 const char *name, *color; 1072 const char *defcolors[3] = {"gray", "orange", "green"}; 1073 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1074 char lname[PETSC_MAX_PATH_LEN]; 1075 PetscReal scale = 2.0; 1076 PetscReal tikzscale = 1.0; 1077 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1078 double tcoords[3]; 1079 PetscScalar *coords; 1080 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; 1081 PetscMPIInt rank, size; 1082 char **names, **colors, **lcolors; 1083 PetscBool flg, lflg; 1084 PetscBT wp = NULL; 1085 PetscInt pEnd, pStart; 1086 1087 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1088 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1089 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1090 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1091 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1092 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1093 PetscCall(DMGetDimension(dm, &dim)); 1094 PetscCall(DMPlexGetDepth(dm, &depth)); 1095 PetscCall(DMGetNumLabels(dm, &numLabels)); 1096 numLabels = PetscMax(numLabels, 10); 1097 numColors = 10; 1098 numLColors = 10; 1099 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1100 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1101 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1102 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1103 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1104 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1105 n = 4; 1106 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1107 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1108 n = 4; 1109 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1110 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1111 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1112 if (!useLabels) numLabels = 0; 1113 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1114 if (!useColors) { 1115 numColors = 3; 1116 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1117 } 1118 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1119 if (!useColors) { 1120 numLColors = 4; 1121 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1122 } 1123 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1124 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1125 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1126 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1127 if (depth < dim) plotEdges = PETSC_FALSE; 1128 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1129 1130 /* filter points with labelvalue != labeldefaultvalue */ 1131 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1132 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1133 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1134 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1135 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1136 if (lflg) { 1137 DMLabel lbl; 1138 1139 PetscCall(DMGetLabel(dm, lname, &lbl)); 1140 if (lbl) { 1141 PetscInt val, defval; 1142 1143 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1144 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1145 for (c = pStart; c < pEnd; c++) { 1146 PetscInt *closure = NULL; 1147 PetscInt closureSize; 1148 1149 PetscCall(DMLabelGetValue(lbl, c, &val)); 1150 if (val == defval) continue; 1151 1152 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1153 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1154 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1155 } 1156 } 1157 } 1158 1159 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1160 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1161 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1163 \\documentclass[tikz]{standalone}\n\n\ 1164 \\usepackage{pgflibraryshapes}\n\ 1165 \\usetikzlibrary{backgrounds}\n\ 1166 \\usetikzlibrary{arrows}\n\ 1167 \\begin{document}\n")); 1168 if (size > 1) { 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1170 for (p = 0; p < size; ++p) { 1171 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1172 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1173 } 1174 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1175 } 1176 if (drawHasse) { 1177 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1178 1179 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1180 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1181 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1182 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1183 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1184 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1185 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1186 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1187 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1188 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1189 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1190 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1191 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1192 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1193 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1194 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1195 } 1196 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1197 1198 /* Plot vertices */ 1199 PetscCall(VecGetArray(coordinates, &coords)); 1200 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1201 for (v = vStart; v < vEnd; ++v) { 1202 PetscInt off, dof, d; 1203 PetscBool isLabeled = PETSC_FALSE; 1204 1205 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1206 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1207 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1208 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1209 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1210 for (d = 0; d < dof; ++d) { 1211 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1212 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1213 } 1214 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1215 if (dim == 3) { 1216 PetscReal tmp = tcoords[1]; 1217 tcoords[1] = tcoords[2]; 1218 tcoords[2] = -tmp; 1219 } 1220 for (d = 0; d < dof; ++d) { 1221 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1222 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1223 } 1224 if (drawHasse) color = colors[0 % numColors]; 1225 else color = colors[rank % numColors]; 1226 for (l = 0; l < numLabels; ++l) { 1227 PetscInt val; 1228 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1229 if (val >= 0) { 1230 color = lcolors[l % numLColors]; 1231 isLabeled = PETSC_TRUE; 1232 break; 1233 } 1234 } 1235 if (drawNumbers[0]) { 1236 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1237 } else if (drawColors[0]) { 1238 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1239 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1240 } 1241 PetscCall(VecRestoreArray(coordinates, &coords)); 1242 PetscCall(PetscViewerFlush(viewer)); 1243 /* Plot edges */ 1244 if (plotEdges) { 1245 PetscCall(VecGetArray(coordinates, &coords)); 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1247 for (e = eStart; e < eEnd; ++e) { 1248 const PetscInt *cone; 1249 PetscInt coneSize, offA, offB, dof, d; 1250 1251 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1252 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1253 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1254 PetscCall(DMPlexGetCone(dm, e, &cone)); 1255 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1256 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1257 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1258 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1259 for (d = 0; d < dof; ++d) { 1260 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1261 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1262 } 1263 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1264 if (dim == 3) { 1265 PetscReal tmp = tcoords[1]; 1266 tcoords[1] = tcoords[2]; 1267 tcoords[2] = -tmp; 1268 } 1269 for (d = 0; d < dof; ++d) { 1270 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1271 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1272 } 1273 if (drawHasse) color = colors[1 % numColors]; 1274 else color = colors[rank % numColors]; 1275 for (l = 0; l < numLabels; ++l) { 1276 PetscInt val; 1277 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1278 if (val >= 0) { 1279 color = lcolors[l % numLColors]; 1280 break; 1281 } 1282 } 1283 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1284 } 1285 PetscCall(VecRestoreArray(coordinates, &coords)); 1286 PetscCall(PetscViewerFlush(viewer)); 1287 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1288 } 1289 /* Plot cells */ 1290 if (dim == 3 || !drawNumbers[1]) { 1291 for (e = eStart; e < eEnd; ++e) { 1292 const PetscInt *cone; 1293 1294 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1295 color = colors[rank % numColors]; 1296 for (l = 0; l < numLabels; ++l) { 1297 PetscInt val; 1298 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1299 if (val >= 0) { 1300 color = lcolors[l % numLColors]; 1301 break; 1302 } 1303 } 1304 PetscCall(DMPlexGetCone(dm, e, &cone)); 1305 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1306 } 1307 } else { 1308 DMPolytopeType ct; 1309 1310 /* Drawing a 2D polygon */ 1311 for (c = cStart; c < cEnd; ++c) { 1312 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1313 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1314 if (DMPolytopeTypeIsHybrid(ct)) { 1315 const PetscInt *cone; 1316 PetscInt coneSize, e; 1317 1318 PetscCall(DMPlexGetCone(dm, c, &cone)); 1319 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1320 for (e = 0; e < coneSize; ++e) { 1321 const PetscInt *econe; 1322 1323 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1324 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)); 1325 } 1326 } else { 1327 PetscInt *closure = NULL; 1328 PetscInt closureSize, Nv = 0, v; 1329 1330 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1331 for (p = 0; p < closureSize * 2; p += 2) { 1332 const PetscInt point = closure[p]; 1333 1334 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1335 } 1336 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1337 for (v = 0; v <= Nv; ++v) { 1338 const PetscInt vertex = closure[v % Nv]; 1339 1340 if (v > 0) { 1341 if (plotEdges) { 1342 const PetscInt *edge; 1343 PetscInt endpoints[2], ne; 1344 1345 endpoints[0] = closure[v - 1]; 1346 endpoints[1] = vertex; 1347 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1348 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1349 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1350 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1351 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1352 } 1353 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1354 } 1355 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1356 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1357 } 1358 } 1359 } 1360 for (c = cStart; c < cEnd; ++c) { 1361 double ccoords[3] = {0.0, 0.0, 0.0}; 1362 PetscBool isLabeled = PETSC_FALSE; 1363 PetscScalar *cellCoords = NULL; 1364 const PetscScalar *array; 1365 PetscInt numCoords, cdim, d; 1366 PetscBool isDG; 1367 1368 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1369 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1370 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1371 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1372 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1373 for (p = 0; p < numCoords / cdim; ++p) { 1374 for (d = 0; d < cdim; ++d) { 1375 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1376 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1377 } 1378 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1379 if (cdim == 3) { 1380 PetscReal tmp = tcoords[1]; 1381 tcoords[1] = tcoords[2]; 1382 tcoords[2] = -tmp; 1383 } 1384 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1385 } 1386 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1387 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1388 for (d = 0; d < cdim; ++d) { 1389 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1390 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1391 } 1392 if (drawHasse) color = colors[depth % numColors]; 1393 else color = colors[rank % numColors]; 1394 for (l = 0; l < numLabels; ++l) { 1395 PetscInt val; 1396 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1397 if (val >= 0) { 1398 color = lcolors[l % numLColors]; 1399 isLabeled = PETSC_TRUE; 1400 break; 1401 } 1402 } 1403 if (drawNumbers[dim]) { 1404 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1405 } else if (drawColors[dim]) { 1406 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1407 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1408 } 1409 if (drawHasse) { 1410 int height = 0; 1411 1412 color = colors[depth % numColors]; 1413 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1414 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1418 1419 if (depth > 2) { 1420 color = colors[1 % numColors]; 1421 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1422 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1424 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1425 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1426 } 1427 1428 color = colors[1 % numColors]; 1429 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1430 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1431 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1432 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1433 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1434 1435 color = colors[0 % numColors]; 1436 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1437 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1438 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1439 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1440 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1441 1442 for (p = pStart; p < pEnd; ++p) { 1443 const PetscInt *cone; 1444 PetscInt coneSize, cp; 1445 1446 PetscCall(DMPlexGetCone(dm, p, &cone)); 1447 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1448 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1449 } 1450 } 1451 PetscCall(PetscViewerFlush(viewer)); 1452 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1453 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1454 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1455 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1456 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1457 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1458 PetscCall(PetscFree3(names, colors, lcolors)); 1459 PetscCall(PetscBTDestroy(&wp)); 1460 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1461 Vec cown, acown; 1462 VecScatter sct; 1463 ISLocalToGlobalMapping g2l; 1464 IS gid, acis; 1465 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1466 MPI_Group ggroup, ngroup; 1467 PetscScalar *array, nid; 1468 const PetscInt *idxs; 1469 PetscInt *idxs2, *start, *adjacency, *work; 1470 PetscInt64 lm[3], gm[3]; 1471 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1472 PetscMPIInt d1, d2, rank; 1473 1474 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1475 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1476 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1477 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1478 #endif 1479 if (ncomm != MPI_COMM_NULL) { 1480 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1481 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1482 d1 = 0; 1483 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1484 nid = d2; 1485 PetscCallMPI(MPI_Group_free(&ggroup)); 1486 PetscCallMPI(MPI_Group_free(&ngroup)); 1487 PetscCallMPI(MPI_Comm_free(&ncomm)); 1488 } else nid = 0.0; 1489 1490 /* Get connectivity */ 1491 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1492 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1493 1494 /* filter overlapped local cells */ 1495 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1496 PetscCall(ISGetIndices(gid, &idxs)); 1497 PetscCall(ISGetLocalSize(gid, &cum)); 1498 PetscCall(PetscMalloc1(cum, &idxs2)); 1499 for (c = cStart, cum = 0; c < cEnd; c++) { 1500 if (idxs[c - cStart] < 0) continue; 1501 idxs2[cum++] = idxs[c - cStart]; 1502 } 1503 PetscCall(ISRestoreIndices(gid, &idxs)); 1504 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1505 PetscCall(ISDestroy(&gid)); 1506 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1507 1508 /* support for node-aware cell locality */ 1509 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1510 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1511 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1512 PetscCall(VecGetArray(cown, &array)); 1513 for (c = 0; c < numVertices; c++) array[c] = nid; 1514 PetscCall(VecRestoreArray(cown, &array)); 1515 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1516 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1517 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1518 PetscCall(ISDestroy(&acis)); 1519 PetscCall(VecScatterDestroy(&sct)); 1520 PetscCall(VecDestroy(&cown)); 1521 1522 /* compute edgeCut */ 1523 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1524 PetscCall(PetscMalloc1(cum, &work)); 1525 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1526 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1527 PetscCall(ISDestroy(&gid)); 1528 PetscCall(VecGetArray(acown, &array)); 1529 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1530 PetscInt totl; 1531 1532 totl = start[c + 1] - start[c]; 1533 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1534 for (i = 0; i < totl; i++) { 1535 if (work[i] < 0) { 1536 ect += 1; 1537 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1538 } 1539 } 1540 } 1541 PetscCall(PetscFree(work)); 1542 PetscCall(VecRestoreArray(acown, &array)); 1543 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1544 lm[1] = -numVertices; 1545 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1546 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1547 lm[0] = ect; /* edgeCut */ 1548 lm[1] = ectn; /* node-aware edgeCut */ 1549 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1550 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1551 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1552 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1553 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1554 #else 1555 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1556 #endif 1557 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1558 PetscCall(PetscFree(start)); 1559 PetscCall(PetscFree(adjacency)); 1560 PetscCall(VecDestroy(&acown)); 1561 } else { 1562 const char *name; 1563 PetscInt *sizes, *hybsizes, *ghostsizes; 1564 PetscInt locDepth, depth, cellHeight, dim, d; 1565 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1566 PetscInt numLabels, l, maxSize = 17; 1567 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1568 MPI_Comm comm; 1569 PetscMPIInt size, rank; 1570 1571 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1572 PetscCallMPI(MPI_Comm_size(comm, &size)); 1573 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1574 PetscCall(DMGetDimension(dm, &dim)); 1575 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1576 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1577 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1578 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1579 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1580 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1581 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1582 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1583 gcNum = gcEnd - gcStart; 1584 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1585 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1586 for (d = 0; d <= depth; d++) { 1587 PetscInt Nc[2] = {0, 0}, ict; 1588 1589 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1590 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1591 ict = ct0; 1592 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1593 ct0 = (DMPolytopeType)ict; 1594 for (p = pStart; p < pEnd; ++p) { 1595 DMPolytopeType ct; 1596 1597 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1598 if (ct == ct0) ++Nc[0]; 1599 else ++Nc[1]; 1600 } 1601 if (size < maxSize) { 1602 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1603 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1604 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1605 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1606 for (p = 0; p < size; ++p) { 1607 if (rank == 0) { 1608 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1609 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1610 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1611 } 1612 } 1613 } else { 1614 PetscInt locMinMax[2]; 1615 1616 locMinMax[0] = Nc[0] + Nc[1]; 1617 locMinMax[1] = Nc[0] + Nc[1]; 1618 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1619 locMinMax[0] = Nc[1]; 1620 locMinMax[1] = Nc[1]; 1621 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1622 if (d == depth) { 1623 locMinMax[0] = gcNum; 1624 locMinMax[1] = gcNum; 1625 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1626 } 1627 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1628 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1629 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1630 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1631 } 1632 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1633 } 1634 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1635 { 1636 const PetscReal *maxCell; 1637 const PetscReal *L; 1638 PetscBool localized; 1639 1640 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1641 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1642 if (L || localized) { 1643 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1644 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1645 if (L) { 1646 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1647 for (d = 0; d < dim; ++d) { 1648 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1649 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1650 } 1651 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1652 } 1653 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1654 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1655 } 1656 } 1657 PetscCall(DMGetNumLabels(dm, &numLabels)); 1658 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1659 for (l = 0; l < numLabels; ++l) { 1660 DMLabel label; 1661 const char *name; 1662 PetscInt *values; 1663 PetscInt numValues, v; 1664 1665 PetscCall(DMGetLabelName(dm, l, &name)); 1666 PetscCall(DMGetLabel(dm, name, &label)); 1667 PetscCall(DMLabelGetNumValues(label, &numValues)); 1668 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1669 1670 { // Extract array of DMLabel values so it can be sorted 1671 IS is_values; 1672 const PetscInt *is_values_local = NULL; 1673 1674 PetscCall(DMLabelGetValueIS(label, &is_values)); 1675 PetscCall(ISGetIndices(is_values, &is_values_local)); 1676 PetscCall(PetscMalloc1(numValues, &values)); 1677 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1678 PetscCall(PetscSortInt(numValues, values)); 1679 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1680 PetscCall(ISDestroy(&is_values)); 1681 } 1682 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1683 for (v = 0; v < numValues; ++v) { 1684 PetscInt size; 1685 1686 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1687 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1688 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1689 } 1690 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1691 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1692 PetscCall(PetscFree(values)); 1693 } 1694 { 1695 char **labelNames; 1696 PetscInt Nl = numLabels; 1697 PetscBool flg; 1698 1699 PetscCall(PetscMalloc1(Nl, &labelNames)); 1700 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1701 for (l = 0; l < Nl; ++l) { 1702 DMLabel label; 1703 1704 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1705 if (flg) { 1706 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1707 PetscCall(DMLabelView(label, viewer)); 1708 } 1709 PetscCall(PetscFree(labelNames[l])); 1710 } 1711 PetscCall(PetscFree(labelNames)); 1712 } 1713 /* If no fields are specified, people do not want to see adjacency */ 1714 if (dm->Nf) { 1715 PetscInt f; 1716 1717 for (f = 0; f < dm->Nf; ++f) { 1718 const char *name; 1719 1720 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1721 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1722 PetscCall(PetscViewerASCIIPushTab(viewer)); 1723 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1724 if (dm->fields[f].adjacency[0]) { 1725 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1726 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1727 } else { 1728 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1729 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1730 } 1731 PetscCall(PetscViewerASCIIPopTab(viewer)); 1732 } 1733 } 1734 PetscCall(DMGetCoarseDM(dm, &cdm)); 1735 if (cdm) { 1736 PetscCall(PetscViewerASCIIPushTab(viewer)); 1737 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1738 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1739 PetscCall(PetscViewerASCIIPopTab(viewer)); 1740 } 1741 } 1742 PetscFunctionReturn(PETSC_SUCCESS); 1743 } 1744 1745 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1746 { 1747 DMPolytopeType ct; 1748 PetscMPIInt rank; 1749 PetscInt cdim; 1750 1751 PetscFunctionBegin; 1752 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1753 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1754 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1755 switch (ct) { 1756 case DM_POLYTOPE_SEGMENT: 1757 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1758 switch (cdim) { 1759 case 1: { 1760 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1761 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1762 1763 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1764 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1765 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1766 } break; 1767 case 2: { 1768 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1769 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1770 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1771 1772 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1773 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)); 1774 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)); 1775 } break; 1776 default: 1777 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1778 } 1779 break; 1780 case DM_POLYTOPE_TRIANGLE: 1781 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)); 1782 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1783 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1784 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1785 break; 1786 case DM_POLYTOPE_QUADRILATERAL: 1787 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)); 1788 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)); 1789 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1790 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1791 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1792 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1793 break; 1794 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1795 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)); 1796 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)); 1797 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1798 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1799 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1800 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1801 break; 1802 case DM_POLYTOPE_FV_GHOST: 1803 break; 1804 default: 1805 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1806 } 1807 PetscFunctionReturn(PETSC_SUCCESS); 1808 } 1809 1810 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1811 { 1812 PetscReal centroid[2] = {0., 0.}; 1813 PetscMPIInt rank; 1814 PetscInt fillColor; 1815 1816 PetscFunctionBegin; 1817 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1818 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1819 for (PetscInt v = 0; v < Nv; ++v) { 1820 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1821 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1822 } 1823 for (PetscInt e = 0; e < Nv; ++e) { 1824 refCoords[0] = refVertices[e * 2 + 0]; 1825 refCoords[1] = refVertices[e * 2 + 1]; 1826 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1827 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1828 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1829 } 1830 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1831 for (PetscInt d = 0; d < edgeDiv; ++d) { 1832 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)); 1833 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1834 } 1835 } 1836 PetscFunctionReturn(PETSC_SUCCESS); 1837 } 1838 1839 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1840 { 1841 DMPolytopeType ct; 1842 1843 PetscFunctionBegin; 1844 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1845 switch (ct) { 1846 case DM_POLYTOPE_TRIANGLE: { 1847 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1848 1849 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1850 } break; 1851 case DM_POLYTOPE_QUADRILATERAL: { 1852 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1853 1854 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1855 } break; 1856 default: 1857 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1858 } 1859 PetscFunctionReturn(PETSC_SUCCESS); 1860 } 1861 1862 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1863 { 1864 PetscDraw draw; 1865 DM cdm; 1866 PetscSection coordSection; 1867 Vec coordinates; 1868 PetscReal xyl[3], xyr[3]; 1869 PetscReal *refCoords, *edgeCoords; 1870 PetscBool isnull, drawAffine; 1871 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1872 1873 PetscFunctionBegin; 1874 PetscCall(DMGetCoordinateDim(dm, &dim)); 1875 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1876 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1877 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1878 edgeDiv = cDegree + 1; 1879 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1880 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1881 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1882 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1883 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1884 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1885 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1886 1887 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1888 PetscCall(PetscDrawIsNull(draw, &isnull)); 1889 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1890 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1891 1892 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1893 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1894 PetscCall(PetscDrawClear(draw)); 1895 1896 for (c = cStart; c < cEnd; ++c) { 1897 PetscScalar *coords = NULL; 1898 const PetscScalar *coords_arr; 1899 PetscInt numCoords; 1900 PetscBool isDG; 1901 1902 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1903 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1904 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1905 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1906 } 1907 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1908 PetscCall(PetscDrawFlush(draw)); 1909 PetscCall(PetscDrawPause(draw)); 1910 PetscCall(PetscDrawSave(draw)); 1911 PetscFunctionReturn(PETSC_SUCCESS); 1912 } 1913 1914 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1915 { 1916 DM odm = dm, rdm = dm, cdm; 1917 PetscFE fe; 1918 PetscSpace sp; 1919 PetscClassId id; 1920 PetscInt degree; 1921 PetscBool hoView = PETSC_TRUE; 1922 1923 PetscFunctionBegin; 1924 PetscObjectOptionsBegin((PetscObject)dm); 1925 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1926 PetscOptionsEnd(); 1927 PetscCall(PetscObjectReference((PetscObject)dm)); 1928 *hdm = dm; 1929 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1930 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1931 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1932 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1933 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1934 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1935 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1936 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1937 DM cdm, rcdm; 1938 Mat In; 1939 Vec cl, rcl; 1940 1941 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1942 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1943 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1944 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1945 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1946 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1947 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1948 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1949 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1950 PetscCall(MatMult(In, cl, rcl)); 1951 PetscCall(MatDestroy(&In)); 1952 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1953 PetscCall(DMDestroy(&odm)); 1954 odm = rdm; 1955 } 1956 *hdm = rdm; 1957 PetscFunctionReturn(PETSC_SUCCESS); 1958 } 1959 1960 #if defined(PETSC_HAVE_EXODUSII) 1961 #include <exodusII.h> 1962 #include <petscviewerexodusii.h> 1963 #endif 1964 1965 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1966 { 1967 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1968 char name[PETSC_MAX_PATH_LEN]; 1969 1970 PetscFunctionBegin; 1971 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1972 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1973 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1974 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1975 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1976 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1977 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1978 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1979 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1980 if (iascii) { 1981 PetscViewerFormat format; 1982 PetscCall(PetscViewerGetFormat(viewer, &format)); 1983 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1984 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1985 } else if (ishdf5) { 1986 #if defined(PETSC_HAVE_HDF5) 1987 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1988 #else 1989 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1990 #endif 1991 } else if (isvtk) { 1992 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1993 } else if (isdraw) { 1994 DM hdm; 1995 1996 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1997 PetscCall(DMPlexView_Draw(hdm, viewer)); 1998 PetscCall(DMDestroy(&hdm)); 1999 } else if (isglvis) { 2000 PetscCall(DMPlexView_GLVis(dm, viewer)); 2001 #if defined(PETSC_HAVE_EXODUSII) 2002 } else if (isexodus) { 2003 /* 2004 exodusII requires that all sets be part of exactly one cell set. 2005 If the dm does not have a "Cell Sets" label defined, we create one 2006 with ID 1, containing all cells. 2007 Note that if the Cell Sets label is defined but does not cover all cells, 2008 we may still have a problem. This should probably be checked here or in the viewer; 2009 */ 2010 PetscInt numCS; 2011 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2012 if (!numCS) { 2013 PetscInt cStart, cEnd, c; 2014 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2015 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2016 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2017 } 2018 PetscCall(DMView_PlexExodusII(dm, viewer)); 2019 #endif 2020 #if defined(PETSC_HAVE_CGNS) 2021 } else if (iscgns) { 2022 PetscCall(DMView_PlexCGNS(dm, viewer)); 2023 #endif 2024 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2025 /* Optionally view the partition */ 2026 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2027 if (flg) { 2028 Vec ranks; 2029 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2030 PetscCall(VecView(ranks, viewer)); 2031 PetscCall(VecDestroy(&ranks)); 2032 } 2033 /* Optionally view a label */ 2034 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2035 if (flg) { 2036 DMLabel label; 2037 Vec val; 2038 2039 PetscCall(DMGetLabel(dm, name, &label)); 2040 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2041 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2042 PetscCall(VecView(val, viewer)); 2043 PetscCall(VecDestroy(&val)); 2044 } 2045 PetscFunctionReturn(PETSC_SUCCESS); 2046 } 2047 2048 /*@ 2049 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2050 2051 Collective 2052 2053 Input Parameters: 2054 + dm - The `DM` whose topology is to be saved 2055 - viewer - The `PetscViewer` to save it in 2056 2057 Level: advanced 2058 2059 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2060 @*/ 2061 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2062 { 2063 PetscBool ishdf5; 2064 2065 PetscFunctionBegin; 2066 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2067 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2068 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2069 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2070 if (ishdf5) { 2071 #if defined(PETSC_HAVE_HDF5) 2072 PetscViewerFormat format; 2073 PetscCall(PetscViewerGetFormat(viewer, &format)); 2074 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2075 IS globalPointNumbering; 2076 2077 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2078 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2079 PetscCall(ISDestroy(&globalPointNumbering)); 2080 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2081 #else 2082 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2083 #endif 2084 } 2085 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2086 PetscFunctionReturn(PETSC_SUCCESS); 2087 } 2088 2089 /*@ 2090 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2091 2092 Collective 2093 2094 Input Parameters: 2095 + dm - The `DM` whose coordinates are to be saved 2096 - viewer - The `PetscViewer` for saving 2097 2098 Level: advanced 2099 2100 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2101 @*/ 2102 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2103 { 2104 PetscBool ishdf5; 2105 2106 PetscFunctionBegin; 2107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2108 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2109 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2110 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2111 if (ishdf5) { 2112 #if defined(PETSC_HAVE_HDF5) 2113 PetscViewerFormat format; 2114 PetscCall(PetscViewerGetFormat(viewer, &format)); 2115 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2116 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2117 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2118 #else 2119 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2120 #endif 2121 } 2122 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2123 PetscFunctionReturn(PETSC_SUCCESS); 2124 } 2125 2126 /*@ 2127 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2128 2129 Collective 2130 2131 Input Parameters: 2132 + dm - The `DM` whose labels are to be saved 2133 - viewer - The `PetscViewer` for saving 2134 2135 Level: advanced 2136 2137 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2138 @*/ 2139 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2140 { 2141 PetscBool ishdf5; 2142 2143 PetscFunctionBegin; 2144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2145 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2146 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2147 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2148 if (ishdf5) { 2149 #if defined(PETSC_HAVE_HDF5) 2150 IS globalPointNumbering; 2151 PetscViewerFormat format; 2152 2153 PetscCall(PetscViewerGetFormat(viewer, &format)); 2154 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2155 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2156 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2157 PetscCall(ISDestroy(&globalPointNumbering)); 2158 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2159 #else 2160 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2161 #endif 2162 } 2163 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2164 PetscFunctionReturn(PETSC_SUCCESS); 2165 } 2166 2167 /*@ 2168 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2169 2170 Collective 2171 2172 Input Parameters: 2173 + dm - The `DM` that contains the topology on which the section to be saved is defined 2174 . viewer - The `PetscViewer` for saving 2175 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2176 2177 Level: advanced 2178 2179 Notes: 2180 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. 2181 2182 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. 2183 2184 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2185 @*/ 2186 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2187 { 2188 PetscBool ishdf5; 2189 2190 PetscFunctionBegin; 2191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2192 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2193 if (!sectiondm) sectiondm = dm; 2194 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2195 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2196 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2197 if (ishdf5) { 2198 #if defined(PETSC_HAVE_HDF5) 2199 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2200 #else 2201 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2202 #endif 2203 } 2204 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2205 PetscFunctionReturn(PETSC_SUCCESS); 2206 } 2207 2208 /*@ 2209 DMPlexGlobalVectorView - Saves a global vector 2210 2211 Collective 2212 2213 Input Parameters: 2214 + dm - The `DM` that represents the topology 2215 . viewer - The `PetscViewer` to save data with 2216 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2217 - vec - The global vector to be saved 2218 2219 Level: advanced 2220 2221 Notes: 2222 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. 2223 2224 Calling sequence: 2225 .vb 2226 DMCreate(PETSC_COMM_WORLD, &dm); 2227 DMSetType(dm, DMPLEX); 2228 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2229 DMClone(dm, §iondm); 2230 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2231 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2232 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2233 PetscSectionSetChart(section, pStart, pEnd); 2234 PetscSectionSetUp(section); 2235 DMSetLocalSection(sectiondm, section); 2236 PetscSectionDestroy(§ion); 2237 DMGetGlobalVector(sectiondm, &vec); 2238 PetscObjectSetName((PetscObject)vec, "vec_name"); 2239 DMPlexTopologyView(dm, viewer); 2240 DMPlexSectionView(dm, viewer, sectiondm); 2241 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2242 DMRestoreGlobalVector(sectiondm, &vec); 2243 DMDestroy(§iondm); 2244 DMDestroy(&dm); 2245 .ve 2246 2247 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2248 @*/ 2249 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2250 { 2251 PetscBool ishdf5; 2252 2253 PetscFunctionBegin; 2254 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2255 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2256 if (!sectiondm) sectiondm = dm; 2257 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2258 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2259 /* Check consistency */ 2260 { 2261 PetscSection section; 2262 PetscBool includesConstraints; 2263 PetscInt m, m1; 2264 2265 PetscCall(VecGetLocalSize(vec, &m1)); 2266 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2267 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2268 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2269 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2270 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2271 } 2272 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2273 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2274 if (ishdf5) { 2275 #if defined(PETSC_HAVE_HDF5) 2276 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2277 #else 2278 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2279 #endif 2280 } 2281 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2282 PetscFunctionReturn(PETSC_SUCCESS); 2283 } 2284 2285 /*@ 2286 DMPlexLocalVectorView - Saves a local vector 2287 2288 Collective 2289 2290 Input Parameters: 2291 + dm - The `DM` that represents the topology 2292 . viewer - The `PetscViewer` to save data with 2293 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2294 - vec - The local vector to be saved 2295 2296 Level: advanced 2297 2298 Note: 2299 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. 2300 2301 Calling sequence: 2302 .vb 2303 DMCreate(PETSC_COMM_WORLD, &dm); 2304 DMSetType(dm, DMPLEX); 2305 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2306 DMClone(dm, §iondm); 2307 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2308 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2309 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2310 PetscSectionSetChart(section, pStart, pEnd); 2311 PetscSectionSetUp(section); 2312 DMSetLocalSection(sectiondm, section); 2313 DMGetLocalVector(sectiondm, &vec); 2314 PetscObjectSetName((PetscObject)vec, "vec_name"); 2315 DMPlexTopologyView(dm, viewer); 2316 DMPlexSectionView(dm, viewer, sectiondm); 2317 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2318 DMRestoreLocalVector(sectiondm, &vec); 2319 DMDestroy(§iondm); 2320 DMDestroy(&dm); 2321 .ve 2322 2323 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2324 @*/ 2325 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2326 { 2327 PetscBool ishdf5; 2328 2329 PetscFunctionBegin; 2330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2331 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2332 if (!sectiondm) sectiondm = dm; 2333 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2334 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2335 /* Check consistency */ 2336 { 2337 PetscSection section; 2338 PetscBool includesConstraints; 2339 PetscInt m, m1; 2340 2341 PetscCall(VecGetLocalSize(vec, &m1)); 2342 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2343 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2344 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2345 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2346 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2347 } 2348 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2349 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2350 if (ishdf5) { 2351 #if defined(PETSC_HAVE_HDF5) 2352 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2353 #else 2354 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2355 #endif 2356 } 2357 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2358 PetscFunctionReturn(PETSC_SUCCESS); 2359 } 2360 2361 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2362 { 2363 PetscBool ishdf5; 2364 2365 PetscFunctionBegin; 2366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2367 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2368 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2369 if (ishdf5) { 2370 #if defined(PETSC_HAVE_HDF5) 2371 PetscViewerFormat format; 2372 PetscCall(PetscViewerGetFormat(viewer, &format)); 2373 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2374 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2375 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2376 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2377 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2378 PetscFunctionReturn(PETSC_SUCCESS); 2379 #else 2380 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2381 #endif 2382 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2383 } 2384 2385 /*@ 2386 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2387 2388 Collective 2389 2390 Input Parameters: 2391 + dm - The `DM` into which the topology is loaded 2392 - viewer - The `PetscViewer` for the saved topology 2393 2394 Output Parameter: 2395 . 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; 2396 `NULL` if unneeded 2397 2398 Level: advanced 2399 2400 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2401 `PetscViewer`, `PetscSF` 2402 @*/ 2403 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2404 { 2405 PetscBool ishdf5; 2406 2407 PetscFunctionBegin; 2408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2409 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2410 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2411 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2412 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2413 if (ishdf5) { 2414 #if defined(PETSC_HAVE_HDF5) 2415 PetscViewerFormat format; 2416 PetscCall(PetscViewerGetFormat(viewer, &format)); 2417 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2418 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2419 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2420 #else 2421 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2422 #endif 2423 } 2424 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2425 PetscFunctionReturn(PETSC_SUCCESS); 2426 } 2427 2428 /*@ 2429 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2430 2431 Collective 2432 2433 Input Parameters: 2434 + dm - The `DM` into which the coordinates are loaded 2435 . viewer - The `PetscViewer` for the saved coordinates 2436 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2437 2438 Level: advanced 2439 2440 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2441 `PetscSF`, `PetscViewer` 2442 @*/ 2443 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2444 { 2445 PetscBool ishdf5; 2446 2447 PetscFunctionBegin; 2448 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2449 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2450 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2451 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2452 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2453 if (ishdf5) { 2454 #if defined(PETSC_HAVE_HDF5) 2455 PetscViewerFormat format; 2456 PetscCall(PetscViewerGetFormat(viewer, &format)); 2457 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2458 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2459 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2460 #else 2461 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2462 #endif 2463 } 2464 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2465 PetscFunctionReturn(PETSC_SUCCESS); 2466 } 2467 2468 /*@ 2469 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2470 2471 Collective 2472 2473 Input Parameters: 2474 + dm - The `DM` into which the labels are loaded 2475 . viewer - The `PetscViewer` for the saved labels 2476 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2477 2478 Level: advanced 2479 2480 Note: 2481 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2482 2483 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2484 `PetscSF`, `PetscViewer` 2485 @*/ 2486 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2487 { 2488 PetscBool ishdf5; 2489 2490 PetscFunctionBegin; 2491 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2492 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2493 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2494 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2495 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2496 if (ishdf5) { 2497 #if defined(PETSC_HAVE_HDF5) 2498 PetscViewerFormat format; 2499 2500 PetscCall(PetscViewerGetFormat(viewer, &format)); 2501 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2502 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2503 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2504 #else 2505 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2506 #endif 2507 } 2508 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2509 PetscFunctionReturn(PETSC_SUCCESS); 2510 } 2511 2512 /*@ 2513 DMPlexSectionLoad - Loads section into a `DMPLEX` 2514 2515 Collective 2516 2517 Input Parameters: 2518 + dm - The `DM` that represents the topology 2519 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2520 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2521 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2522 2523 Output Parameters: 2524 + 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) 2525 - 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) 2526 2527 Level: advanced 2528 2529 Notes: 2530 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. 2531 2532 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. 2533 2534 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. 2535 2536 Example using 2 processes: 2537 .vb 2538 NX (number of points on dm): 4 2539 sectionA : the on-disk section 2540 vecA : a vector associated with sectionA 2541 sectionB : sectiondm's local section constructed in this function 2542 vecB (local) : a vector associated with sectiondm's local section 2543 vecB (global) : a vector associated with sectiondm's global section 2544 2545 rank 0 rank 1 2546 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2547 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2548 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2549 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2550 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2551 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2552 sectionB->atlasDof : 1 0 1 | 1 3 2553 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2554 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2555 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2556 .ve 2557 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2558 2559 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2560 @*/ 2561 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2562 { 2563 PetscBool ishdf5; 2564 2565 PetscFunctionBegin; 2566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2567 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2568 if (!sectiondm) sectiondm = dm; 2569 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2570 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2571 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2572 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2573 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2574 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2575 if (ishdf5) { 2576 #if defined(PETSC_HAVE_HDF5) 2577 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2578 #else 2579 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2580 #endif 2581 } 2582 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2583 PetscFunctionReturn(PETSC_SUCCESS); 2584 } 2585 2586 /*@ 2587 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2588 2589 Collective 2590 2591 Input Parameters: 2592 + dm - The `DM` that represents the topology 2593 . viewer - The `PetscViewer` that represents the on-disk vector data 2594 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2595 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2596 - vec - The global vector to set values of 2597 2598 Level: advanced 2599 2600 Notes: 2601 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. 2602 2603 Calling sequence: 2604 .vb 2605 DMCreate(PETSC_COMM_WORLD, &dm); 2606 DMSetType(dm, DMPLEX); 2607 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2608 DMPlexTopologyLoad(dm, viewer, &sfX); 2609 DMClone(dm, §iondm); 2610 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2611 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2612 DMGetGlobalVector(sectiondm, &vec); 2613 PetscObjectSetName((PetscObject)vec, "vec_name"); 2614 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2615 DMRestoreGlobalVector(sectiondm, &vec); 2616 PetscSFDestroy(&gsf); 2617 PetscSFDestroy(&sfX); 2618 DMDestroy(§iondm); 2619 DMDestroy(&dm); 2620 .ve 2621 2622 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2623 `PetscSF`, `PetscViewer` 2624 @*/ 2625 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2626 { 2627 PetscBool ishdf5; 2628 2629 PetscFunctionBegin; 2630 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2631 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2632 if (!sectiondm) sectiondm = dm; 2633 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2634 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2635 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2636 /* Check consistency */ 2637 { 2638 PetscSection section; 2639 PetscBool includesConstraints; 2640 PetscInt m, m1; 2641 2642 PetscCall(VecGetLocalSize(vec, &m1)); 2643 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2644 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2645 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2646 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2647 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2648 } 2649 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2650 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2651 if (ishdf5) { 2652 #if defined(PETSC_HAVE_HDF5) 2653 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2654 #else 2655 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2656 #endif 2657 } 2658 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2659 PetscFunctionReturn(PETSC_SUCCESS); 2660 } 2661 2662 /*@ 2663 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2664 2665 Collective 2666 2667 Input Parameters: 2668 + dm - The `DM` that represents the topology 2669 . viewer - The `PetscViewer` that represents the on-disk vector data 2670 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2671 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2672 - vec - The local vector to set values of 2673 2674 Level: advanced 2675 2676 Notes: 2677 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. 2678 2679 Calling sequence: 2680 .vb 2681 DMCreate(PETSC_COMM_WORLD, &dm); 2682 DMSetType(dm, DMPLEX); 2683 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2684 DMPlexTopologyLoad(dm, viewer, &sfX); 2685 DMClone(dm, §iondm); 2686 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2687 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2688 DMGetLocalVector(sectiondm, &vec); 2689 PetscObjectSetName((PetscObject)vec, "vec_name"); 2690 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2691 DMRestoreLocalVector(sectiondm, &vec); 2692 PetscSFDestroy(&lsf); 2693 PetscSFDestroy(&sfX); 2694 DMDestroy(§iondm); 2695 DMDestroy(&dm); 2696 .ve 2697 2698 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2699 `PetscSF`, `PetscViewer` 2700 @*/ 2701 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2702 { 2703 PetscBool ishdf5; 2704 2705 PetscFunctionBegin; 2706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2707 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2708 if (!sectiondm) sectiondm = dm; 2709 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2710 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2711 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2712 /* Check consistency */ 2713 { 2714 PetscSection section; 2715 PetscBool includesConstraints; 2716 PetscInt m, m1; 2717 2718 PetscCall(VecGetLocalSize(vec, &m1)); 2719 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2720 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2721 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2722 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2723 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2724 } 2725 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2726 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2727 if (ishdf5) { 2728 #if defined(PETSC_HAVE_HDF5) 2729 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2730 #else 2731 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2732 #endif 2733 } 2734 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2735 PetscFunctionReturn(PETSC_SUCCESS); 2736 } 2737 2738 PetscErrorCode DMDestroy_Plex(DM dm) 2739 { 2740 DM_Plex *mesh = (DM_Plex *)dm->data; 2741 2742 PetscFunctionBegin; 2743 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2744 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2745 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2746 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2747 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2748 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2749 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2750 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2751 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2752 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2753 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2754 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2755 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2756 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2757 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2758 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2759 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2760 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2761 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2762 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2763 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2764 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2765 PetscCall(PetscFree(mesh->cones)); 2766 PetscCall(PetscFree(mesh->coneOrientations)); 2767 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2768 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2769 PetscCall(PetscFree(mesh->supports)); 2770 PetscCall(PetscFree(mesh->cellTypes)); 2771 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2772 PetscCall(PetscFree(mesh->tetgenOpts)); 2773 PetscCall(PetscFree(mesh->triangleOpts)); 2774 PetscCall(PetscFree(mesh->transformType)); 2775 PetscCall(PetscFree(mesh->distributionName)); 2776 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2777 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2778 PetscCall(ISDestroy(&mesh->subpointIS)); 2779 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2780 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2781 if (mesh->periodic.face_sfs) { 2782 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2783 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2784 } 2785 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2786 if (mesh->periodic.periodic_points) { 2787 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2788 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2789 } 2790 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2791 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2792 PetscCall(ISDestroy(&mesh->anchorIS)); 2793 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2794 PetscCall(PetscFree(mesh->parents)); 2795 PetscCall(PetscFree(mesh->childIDs)); 2796 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2797 PetscCall(PetscFree(mesh->children)); 2798 PetscCall(DMDestroy(&mesh->referenceTree)); 2799 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2800 PetscCall(PetscFree(mesh->neighbors)); 2801 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2802 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2803 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2804 PetscCall(PetscFree(mesh)); 2805 PetscFunctionReturn(PETSC_SUCCESS); 2806 } 2807 2808 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2809 { 2810 PetscSection sectionGlobal, sectionLocal; 2811 PetscInt bs = -1, mbs; 2812 PetscInt localSize, localStart = 0; 2813 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2814 MatType mtype; 2815 ISLocalToGlobalMapping ltog; 2816 2817 PetscFunctionBegin; 2818 PetscCall(MatInitializePackage()); 2819 mtype = dm->mattype; 2820 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2821 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2822 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2823 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2824 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2825 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2826 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2827 PetscCall(MatSetType(*J, mtype)); 2828 PetscCall(MatSetFromOptions(*J)); 2829 PetscCall(MatGetBlockSize(*J, &mbs)); 2830 if (mbs > 1) bs = mbs; 2831 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2832 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2833 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2834 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2835 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2836 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2837 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2838 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2839 if (!isShell) { 2840 // There are three states with pblocks, since block starts can have no dofs: 2841 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2842 // TRUE) Block Start: The first entry in a block has been added 2843 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2844 PetscBT blst; 2845 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2846 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2847 const PetscInt *perm = NULL; 2848 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2849 PetscInt pStart, pEnd, dof, cdof, num_fields; 2850 2851 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2852 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2853 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2854 2855 PetscCall(PetscCalloc1(localSize, &pblocks)); 2856 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2857 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2858 // We need to process in the permuted order to get block sizes right 2859 for (PetscInt point = pStart; point < pEnd; ++point) { 2860 const PetscInt p = perm ? perm[point] : point; 2861 2862 switch (dm->blocking_type) { 2863 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2864 PetscInt bdof, offset; 2865 2866 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2867 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2868 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2869 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2870 if (dof > 0) { 2871 // State change 2872 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2873 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2874 2875 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2876 // Signal block concatenation 2877 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2878 } 2879 dof = dof < 0 ? -(dof + 1) : dof; 2880 bdof = cdof && (dof - cdof) ? 1 : dof; 2881 if (dof) { 2882 if (bs < 0) { 2883 bs = bdof; 2884 } else if (bs != bdof) { 2885 bs = 1; 2886 } 2887 } 2888 } break; 2889 case DM_BLOCKING_FIELD_NODE: { 2890 for (PetscInt field = 0; field < num_fields; field++) { 2891 PetscInt num_comp, bdof, offset; 2892 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2893 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2894 if (dof < 0) continue; 2895 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2896 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2897 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); 2898 PetscInt num_nodes = dof / num_comp; 2899 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2900 // Handle possibly constant block size (unlikely) 2901 bdof = cdof && (dof - cdof) ? 1 : dof; 2902 if (dof) { 2903 if (bs < 0) { 2904 bs = bdof; 2905 } else if (bs != bdof) { 2906 bs = 1; 2907 } 2908 } 2909 } 2910 } break; 2911 } 2912 } 2913 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2914 /* Must have same blocksize on all procs (some might have no points) */ 2915 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2916 bsLocal[1] = bs; 2917 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2918 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2919 else bs = bsMinMax[0]; 2920 bs = PetscMax(1, bs); 2921 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2922 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2923 PetscCall(MatSetBlockSize(*J, bs)); 2924 PetscCall(MatSetUp(*J)); 2925 } else { 2926 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2927 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2928 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2929 } 2930 if (pblocks) { // Consolidate blocks 2931 PetscInt nblocks = 0; 2932 pblocks[0] = PetscAbs(pblocks[0]); 2933 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2934 if (pblocks[i] == 0) continue; 2935 // Negative block size indicates the blocks should be concatenated 2936 if (pblocks[i] < 0) { 2937 pblocks[i] = -pblocks[i]; 2938 pblocks[nblocks - 1] += pblocks[i]; 2939 } else { 2940 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2941 } 2942 for (PetscInt j = 1; j < pblocks[i]; j++) 2943 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); 2944 } 2945 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2946 } 2947 PetscCall(PetscFree(pblocks)); 2948 } 2949 PetscCall(MatSetDM(*J, dm)); 2950 PetscFunctionReturn(PETSC_SUCCESS); 2951 } 2952 2953 /*@ 2954 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2955 2956 Not Collective 2957 2958 Input Parameter: 2959 . dm - The `DMPLEX` 2960 2961 Output Parameter: 2962 . subsection - The subdomain section 2963 2964 Level: developer 2965 2966 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2967 @*/ 2968 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2969 { 2970 DM_Plex *mesh = (DM_Plex *)dm->data; 2971 2972 PetscFunctionBegin; 2973 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2974 if (!mesh->subdomainSection) { 2975 PetscSection section; 2976 PetscSF sf; 2977 2978 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2979 PetscCall(DMGetLocalSection(dm, §ion)); 2980 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2981 PetscCall(PetscSFDestroy(&sf)); 2982 } 2983 *subsection = mesh->subdomainSection; 2984 PetscFunctionReturn(PETSC_SUCCESS); 2985 } 2986 2987 /*@ 2988 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2989 2990 Not Collective 2991 2992 Input Parameter: 2993 . dm - The `DMPLEX` 2994 2995 Output Parameters: 2996 + pStart - The first mesh point 2997 - pEnd - The upper bound for mesh points 2998 2999 Level: beginner 3000 3001 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3002 @*/ 3003 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3004 { 3005 DM_Plex *mesh = (DM_Plex *)dm->data; 3006 3007 PetscFunctionBegin; 3008 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3009 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3010 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3011 PetscFunctionReturn(PETSC_SUCCESS); 3012 } 3013 3014 /*@ 3015 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3016 3017 Not Collective 3018 3019 Input Parameters: 3020 + dm - The `DMPLEX` 3021 . pStart - The first mesh point 3022 - pEnd - The upper bound for mesh points 3023 3024 Level: beginner 3025 3026 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3027 @*/ 3028 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3029 { 3030 DM_Plex *mesh = (DM_Plex *)dm->data; 3031 3032 PetscFunctionBegin; 3033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3034 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3035 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3036 PetscCall(PetscFree(mesh->cellTypes)); 3037 PetscFunctionReturn(PETSC_SUCCESS); 3038 } 3039 3040 /*@ 3041 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3042 3043 Not Collective 3044 3045 Input Parameters: 3046 + dm - The `DMPLEX` 3047 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3048 3049 Output Parameter: 3050 . size - The cone size for point `p` 3051 3052 Level: beginner 3053 3054 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3055 @*/ 3056 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3057 { 3058 DM_Plex *mesh = (DM_Plex *)dm->data; 3059 3060 PetscFunctionBegin; 3061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3062 PetscAssertPointer(size, 3); 3063 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3064 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3065 PetscFunctionReturn(PETSC_SUCCESS); 3066 } 3067 3068 /*@ 3069 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3070 3071 Not Collective 3072 3073 Input Parameters: 3074 + dm - The `DMPLEX` 3075 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3076 - size - The cone size for point `p` 3077 3078 Level: beginner 3079 3080 Note: 3081 This should be called after `DMPlexSetChart()`. 3082 3083 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3084 @*/ 3085 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3086 { 3087 DM_Plex *mesh = (DM_Plex *)dm->data; 3088 3089 PetscFunctionBegin; 3090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3091 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3092 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3093 PetscFunctionReturn(PETSC_SUCCESS); 3094 } 3095 3096 /*@C 3097 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3098 3099 Not Collective 3100 3101 Input Parameters: 3102 + dm - The `DMPLEX` 3103 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3104 3105 Output Parameter: 3106 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3107 3108 Level: beginner 3109 3110 Fortran Notes: 3111 `cone` must be declared with 3112 .vb 3113 PetscInt, pointer :: cone(:) 3114 .ve 3115 3116 You must also call `DMPlexRestoreCone()` after you finish using the array. 3117 `DMPlexRestoreCone()` is not needed/available in C. 3118 3119 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3120 @*/ 3121 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3122 { 3123 DM_Plex *mesh = (DM_Plex *)dm->data; 3124 PetscInt off; 3125 3126 PetscFunctionBegin; 3127 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3128 PetscAssertPointer(cone, 3); 3129 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3130 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3131 PetscFunctionReturn(PETSC_SUCCESS); 3132 } 3133 3134 /*@ 3135 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3136 3137 Not Collective 3138 3139 Input Parameters: 3140 + dm - The `DMPLEX` 3141 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3142 3143 Output Parameters: 3144 + pConesSection - `PetscSection` describing the layout of `pCones` 3145 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3146 3147 Level: intermediate 3148 3149 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3150 @*/ 3151 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3152 { 3153 PetscSection cs, newcs; 3154 PetscInt *cones; 3155 PetscInt *newarr = NULL; 3156 PetscInt n; 3157 3158 PetscFunctionBegin; 3159 PetscCall(DMPlexGetCones(dm, &cones)); 3160 PetscCall(DMPlexGetConeSection(dm, &cs)); 3161 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3162 if (pConesSection) *pConesSection = newcs; 3163 if (pCones) { 3164 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3165 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3166 } 3167 PetscFunctionReturn(PETSC_SUCCESS); 3168 } 3169 3170 /*@ 3171 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3172 3173 Not Collective 3174 3175 Input Parameters: 3176 + dm - The `DMPLEX` 3177 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3178 3179 Output Parameter: 3180 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3181 3182 Level: advanced 3183 3184 Notes: 3185 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3186 3187 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3188 3189 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3190 `DMPlexGetDepth()`, `IS` 3191 @*/ 3192 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3193 { 3194 IS *expandedPointsAll; 3195 PetscInt depth; 3196 3197 PetscFunctionBegin; 3198 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3199 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3200 PetscAssertPointer(expandedPoints, 3); 3201 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3202 *expandedPoints = expandedPointsAll[0]; 3203 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3204 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3205 PetscFunctionReturn(PETSC_SUCCESS); 3206 } 3207 3208 /*@ 3209 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3210 (DAG points of depth 0, i.e., without cones). 3211 3212 Not Collective 3213 3214 Input Parameters: 3215 + dm - The `DMPLEX` 3216 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3217 3218 Output Parameters: 3219 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3220 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3221 - sections - (optional) An array of sections which describe mappings from points to their cone points 3222 3223 Level: advanced 3224 3225 Notes: 3226 Like `DMPlexGetConeTuple()` but recursive. 3227 3228 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. 3229 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3230 3231 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\: 3232 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3233 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3234 3235 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3236 `DMPlexGetDepth()`, `PetscSection`, `IS` 3237 @*/ 3238 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3239 { 3240 const PetscInt *arr0 = NULL, *cone = NULL; 3241 PetscInt *arr = NULL, *newarr = NULL; 3242 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3243 IS *expandedPoints_; 3244 PetscSection *sections_; 3245 3246 PetscFunctionBegin; 3247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3248 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3249 if (depth) PetscAssertPointer(depth, 3); 3250 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3251 if (sections) PetscAssertPointer(sections, 5); 3252 PetscCall(ISGetLocalSize(points, &n)); 3253 PetscCall(ISGetIndices(points, &arr0)); 3254 PetscCall(DMPlexGetDepth(dm, &depth_)); 3255 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3256 PetscCall(PetscCalloc1(depth_, §ions_)); 3257 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3258 for (d = depth_ - 1; d >= 0; d--) { 3259 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3260 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3261 for (i = 0; i < n; i++) { 3262 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3263 if (arr[i] >= start && arr[i] < end) { 3264 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3265 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3266 } else { 3267 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3268 } 3269 } 3270 PetscCall(PetscSectionSetUp(sections_[d])); 3271 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3272 PetscCall(PetscMalloc1(newn, &newarr)); 3273 for (i = 0; i < n; i++) { 3274 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3275 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3276 if (cn > 1) { 3277 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3278 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3279 } else { 3280 newarr[co] = arr[i]; 3281 } 3282 } 3283 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3284 arr = newarr; 3285 n = newn; 3286 } 3287 PetscCall(ISRestoreIndices(points, &arr0)); 3288 *depth = depth_; 3289 if (expandedPoints) *expandedPoints = expandedPoints_; 3290 else { 3291 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3292 PetscCall(PetscFree(expandedPoints_)); 3293 } 3294 if (sections) *sections = sections_; 3295 else { 3296 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3297 PetscCall(PetscFree(sections_)); 3298 } 3299 PetscFunctionReturn(PETSC_SUCCESS); 3300 } 3301 3302 /*@ 3303 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3304 3305 Not Collective 3306 3307 Input Parameters: 3308 + dm - The `DMPLEX` 3309 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3310 3311 Output Parameters: 3312 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3313 . expandedPoints - (optional) An array of recursively expanded cones 3314 - sections - (optional) An array of sections which describe mappings from points to their cone points 3315 3316 Level: advanced 3317 3318 Note: 3319 See `DMPlexGetConeRecursive()` 3320 3321 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3322 `DMPlexGetDepth()`, `IS`, `PetscSection` 3323 @*/ 3324 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3325 { 3326 PetscInt d, depth_; 3327 3328 PetscFunctionBegin; 3329 PetscCall(DMPlexGetDepth(dm, &depth_)); 3330 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3331 if (depth) *depth = 0; 3332 if (expandedPoints) { 3333 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3334 PetscCall(PetscFree(*expandedPoints)); 3335 } 3336 if (sections) { 3337 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3338 PetscCall(PetscFree(*sections)); 3339 } 3340 PetscFunctionReturn(PETSC_SUCCESS); 3341 } 3342 3343 /*@ 3344 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 3345 3346 Not Collective 3347 3348 Input Parameters: 3349 + dm - The `DMPLEX` 3350 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3351 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3352 3353 Level: beginner 3354 3355 Note: 3356 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3357 3358 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3359 @*/ 3360 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3361 { 3362 DM_Plex *mesh = (DM_Plex *)dm->data; 3363 PetscInt dof, off, c; 3364 3365 PetscFunctionBegin; 3366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3367 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3368 if (dof) PetscAssertPointer(cone, 3); 3369 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3370 if (PetscDefined(USE_DEBUG)) { 3371 PetscInt pStart, pEnd; 3372 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3373 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); 3374 for (c = 0; c < dof; ++c) { 3375 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); 3376 mesh->cones[off + c] = cone[c]; 3377 } 3378 } else { 3379 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3380 } 3381 PetscFunctionReturn(PETSC_SUCCESS); 3382 } 3383 3384 /*@C 3385 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3386 3387 Not Collective 3388 3389 Input Parameters: 3390 + dm - The `DMPLEX` 3391 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3392 3393 Output Parameter: 3394 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3395 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3396 3397 Level: beginner 3398 3399 Note: 3400 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3401 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3402 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3403 with the identity. 3404 3405 Fortran Notes: 3406 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3407 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3408 3409 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3410 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3411 @*/ 3412 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3413 { 3414 DM_Plex *mesh = (DM_Plex *)dm->data; 3415 PetscInt off; 3416 3417 PetscFunctionBegin; 3418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3419 if (PetscDefined(USE_DEBUG)) { 3420 PetscInt dof; 3421 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3422 if (dof) PetscAssertPointer(coneOrientation, 3); 3423 } 3424 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3425 3426 *coneOrientation = &mesh->coneOrientations[off]; 3427 PetscFunctionReturn(PETSC_SUCCESS); 3428 } 3429 3430 /*@ 3431 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3432 3433 Not Collective 3434 3435 Input Parameters: 3436 + dm - The `DMPLEX` 3437 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3438 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3439 3440 Level: beginner 3441 3442 Notes: 3443 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3444 3445 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3446 3447 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3448 @*/ 3449 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3450 { 3451 DM_Plex *mesh = (DM_Plex *)dm->data; 3452 PetscInt pStart, pEnd; 3453 PetscInt dof, off, c; 3454 3455 PetscFunctionBegin; 3456 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3457 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3458 if (dof) PetscAssertPointer(coneOrientation, 3); 3459 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3460 if (PetscDefined(USE_DEBUG)) { 3461 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3462 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); 3463 for (c = 0; c < dof; ++c) { 3464 PetscInt cdof, o = coneOrientation[c]; 3465 3466 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3467 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); 3468 mesh->coneOrientations[off + c] = o; 3469 } 3470 } else { 3471 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3472 } 3473 PetscFunctionReturn(PETSC_SUCCESS); 3474 } 3475 3476 /*@ 3477 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3478 3479 Not Collective 3480 3481 Input Parameters: 3482 + dm - The `DMPLEX` 3483 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3484 . conePos - The local index in the cone where the point should be put 3485 - conePoint - The mesh point to insert 3486 3487 Level: beginner 3488 3489 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3490 @*/ 3491 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3492 { 3493 DM_Plex *mesh = (DM_Plex *)dm->data; 3494 PetscInt pStart, pEnd; 3495 PetscInt dof, off; 3496 3497 PetscFunctionBegin; 3498 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3499 if (PetscDefined(USE_DEBUG)) { 3500 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3501 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); 3502 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); 3503 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3504 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); 3505 } 3506 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3507 mesh->cones[off + conePos] = conePoint; 3508 PetscFunctionReturn(PETSC_SUCCESS); 3509 } 3510 3511 /*@ 3512 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3513 3514 Not Collective 3515 3516 Input Parameters: 3517 + dm - The `DMPLEX` 3518 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3519 . conePos - The local index in the cone where the point should be put 3520 - coneOrientation - The point orientation to insert 3521 3522 Level: beginner 3523 3524 Note: 3525 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3526 3527 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3528 @*/ 3529 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3530 { 3531 DM_Plex *mesh = (DM_Plex *)dm->data; 3532 PetscInt pStart, pEnd; 3533 PetscInt dof, off; 3534 3535 PetscFunctionBegin; 3536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3537 if (PetscDefined(USE_DEBUG)) { 3538 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3539 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); 3540 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3541 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); 3542 } 3543 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3544 mesh->coneOrientations[off + conePos] = coneOrientation; 3545 PetscFunctionReturn(PETSC_SUCCESS); 3546 } 3547 3548 /*@C 3549 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3550 3551 Not collective 3552 3553 Input Parameters: 3554 + dm - The DMPlex 3555 - p - The point, which must lie in the chart set with DMPlexSetChart() 3556 3557 Output Parameters: 3558 + cone - An array of points which are on the in-edges for point `p` 3559 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3560 integer giving the prescription for cone traversal. 3561 3562 Level: beginner 3563 3564 Notes: 3565 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3566 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3567 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3568 with the identity. 3569 3570 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3571 3572 Fortran Notes: 3573 `cone` and `ornt` must be declared with 3574 .vb 3575 PetscInt, pointer :: cone(:) 3576 PetscInt, pointer :: ornt(:) 3577 .ve 3578 3579 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3580 @*/ 3581 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3582 { 3583 DM_Plex *mesh = (DM_Plex *)dm->data; 3584 3585 PetscFunctionBegin; 3586 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3587 if (mesh->tr) { 3588 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3589 } else { 3590 PetscInt off; 3591 if (PetscDefined(USE_DEBUG)) { 3592 PetscInt dof; 3593 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3594 if (dof) { 3595 if (cone) PetscAssertPointer(cone, 3); 3596 if (ornt) PetscAssertPointer(ornt, 4); 3597 } 3598 } 3599 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3600 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3601 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3602 } 3603 PetscFunctionReturn(PETSC_SUCCESS); 3604 } 3605 3606 /*@C 3607 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3608 3609 Not Collective 3610 3611 Input Parameters: 3612 + dm - The DMPlex 3613 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3614 . cone - An array of points which are on the in-edges for point p 3615 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3616 integer giving the prescription for cone traversal. 3617 3618 Level: beginner 3619 3620 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3621 @*/ 3622 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3623 { 3624 DM_Plex *mesh = (DM_Plex *)dm->data; 3625 3626 PetscFunctionBegin; 3627 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3628 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3629 PetscFunctionReturn(PETSC_SUCCESS); 3630 } 3631 3632 /*@ 3633 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3634 3635 Not Collective 3636 3637 Input Parameters: 3638 + dm - The `DMPLEX` 3639 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3640 3641 Output Parameter: 3642 . size - The support size for point `p` 3643 3644 Level: beginner 3645 3646 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3647 @*/ 3648 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3649 { 3650 DM_Plex *mesh = (DM_Plex *)dm->data; 3651 3652 PetscFunctionBegin; 3653 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3654 PetscAssertPointer(size, 3); 3655 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3656 PetscFunctionReturn(PETSC_SUCCESS); 3657 } 3658 3659 /*@ 3660 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3661 3662 Not Collective 3663 3664 Input Parameters: 3665 + dm - The `DMPLEX` 3666 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3667 - size - The support size for point `p` 3668 3669 Level: beginner 3670 3671 Note: 3672 This should be called after `DMPlexSetChart()`. 3673 3674 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3675 @*/ 3676 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3677 { 3678 DM_Plex *mesh = (DM_Plex *)dm->data; 3679 3680 PetscFunctionBegin; 3681 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3682 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3683 PetscFunctionReturn(PETSC_SUCCESS); 3684 } 3685 3686 /*@C 3687 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3688 3689 Not Collective 3690 3691 Input Parameters: 3692 + dm - The `DMPLEX` 3693 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3694 3695 Output Parameter: 3696 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3697 3698 Level: beginner 3699 3700 Fortran Notes: 3701 `support` must be declared with 3702 .vb 3703 PetscInt, pointer :: support(:) 3704 .ve 3705 3706 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3707 `DMPlexRestoreSupport()` is not needed/available in C. 3708 3709 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3710 @*/ 3711 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3712 { 3713 DM_Plex *mesh = (DM_Plex *)dm->data; 3714 PetscInt off; 3715 3716 PetscFunctionBegin; 3717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3718 PetscAssertPointer(support, 3); 3719 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3720 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3721 PetscFunctionReturn(PETSC_SUCCESS); 3722 } 3723 3724 /*@ 3725 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3726 3727 Not Collective 3728 3729 Input Parameters: 3730 + dm - The `DMPLEX` 3731 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3732 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3733 3734 Level: beginner 3735 3736 Note: 3737 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3738 3739 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3740 @*/ 3741 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3742 { 3743 DM_Plex *mesh = (DM_Plex *)dm->data; 3744 PetscInt pStart, pEnd; 3745 PetscInt dof, off, c; 3746 3747 PetscFunctionBegin; 3748 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3749 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3750 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3751 if (dof) PetscAssertPointer(support, 3); 3752 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3753 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); 3754 for (c = 0; c < dof; ++c) { 3755 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); 3756 mesh->supports[off + c] = support[c]; 3757 } 3758 PetscFunctionReturn(PETSC_SUCCESS); 3759 } 3760 3761 /*@ 3762 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3763 3764 Not Collective 3765 3766 Input Parameters: 3767 + dm - The `DMPLEX` 3768 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3769 . supportPos - The local index in the cone where the point should be put 3770 - supportPoint - The mesh point to insert 3771 3772 Level: beginner 3773 3774 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3775 @*/ 3776 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3777 { 3778 DM_Plex *mesh = (DM_Plex *)dm->data; 3779 PetscInt pStart, pEnd; 3780 PetscInt dof, off; 3781 3782 PetscFunctionBegin; 3783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3784 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3785 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3786 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3787 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); 3788 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); 3789 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); 3790 mesh->supports[off + supportPos] = supportPoint; 3791 PetscFunctionReturn(PETSC_SUCCESS); 3792 } 3793 3794 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3795 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3796 { 3797 switch (ct) { 3798 case DM_POLYTOPE_SEGMENT: 3799 if (o == -1) return -2; 3800 break; 3801 case DM_POLYTOPE_TRIANGLE: 3802 if (o == -3) return -1; 3803 if (o == -2) return -3; 3804 if (o == -1) return -2; 3805 break; 3806 case DM_POLYTOPE_QUADRILATERAL: 3807 if (o == -4) return -2; 3808 if (o == -3) return -1; 3809 if (o == -2) return -4; 3810 if (o == -1) return -3; 3811 break; 3812 default: 3813 return o; 3814 } 3815 return o; 3816 } 3817 3818 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3819 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3820 { 3821 switch (ct) { 3822 case DM_POLYTOPE_SEGMENT: 3823 if ((o == -2) || (o == 1)) return -1; 3824 if (o == -1) return 0; 3825 break; 3826 case DM_POLYTOPE_TRIANGLE: 3827 if (o == -3) return -2; 3828 if (o == -2) return -1; 3829 if (o == -1) return -3; 3830 break; 3831 case DM_POLYTOPE_QUADRILATERAL: 3832 if (o == -4) return -2; 3833 if (o == -3) return -1; 3834 if (o == -2) return -4; 3835 if (o == -1) return -3; 3836 break; 3837 default: 3838 return o; 3839 } 3840 return o; 3841 } 3842 3843 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3844 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3845 { 3846 PetscInt pStart, pEnd, p; 3847 3848 PetscFunctionBegin; 3849 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3850 for (p = pStart; p < pEnd; ++p) { 3851 const PetscInt *cone, *ornt; 3852 PetscInt coneSize, c; 3853 3854 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3855 PetscCall(DMPlexGetCone(dm, p, &cone)); 3856 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3857 for (c = 0; c < coneSize; ++c) { 3858 DMPolytopeType ct; 3859 const PetscInt o = ornt[c]; 3860 3861 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3862 switch (ct) { 3863 case DM_POLYTOPE_SEGMENT: 3864 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3865 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3866 break; 3867 case DM_POLYTOPE_TRIANGLE: 3868 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3869 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3870 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3871 break; 3872 case DM_POLYTOPE_QUADRILATERAL: 3873 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3874 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3875 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3876 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3877 break; 3878 default: 3879 break; 3880 } 3881 } 3882 } 3883 PetscFunctionReturn(PETSC_SUCCESS); 3884 } 3885 3886 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3887 { 3888 DM_Plex *mesh = (DM_Plex *)dm->data; 3889 3890 PetscFunctionBeginHot; 3891 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3892 if (useCone) { 3893 PetscCall(DMPlexGetConeSize(dm, p, size)); 3894 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3895 } else { 3896 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3897 PetscCall(DMPlexGetSupport(dm, p, arr)); 3898 } 3899 } else { 3900 if (useCone) { 3901 const PetscSection s = mesh->coneSection; 3902 const PetscInt ps = p - s->pStart; 3903 const PetscInt off = s->atlasOff[ps]; 3904 3905 *size = s->atlasDof[ps]; 3906 *arr = mesh->cones + off; 3907 *ornt = mesh->coneOrientations + off; 3908 } else { 3909 const PetscSection s = mesh->supportSection; 3910 const PetscInt ps = p - s->pStart; 3911 const PetscInt off = s->atlasOff[ps]; 3912 3913 *size = s->atlasDof[ps]; 3914 *arr = mesh->supports + off; 3915 } 3916 } 3917 PetscFunctionReturn(PETSC_SUCCESS); 3918 } 3919 3920 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3921 { 3922 DM_Plex *mesh = (DM_Plex *)dm->data; 3923 3924 PetscFunctionBeginHot; 3925 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3926 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3927 } 3928 PetscFunctionReturn(PETSC_SUCCESS); 3929 } 3930 3931 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3932 { 3933 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3934 PetscInt *closure; 3935 const PetscInt *tmp = NULL, *tmpO = NULL; 3936 PetscInt off = 0, tmpSize, t; 3937 3938 PetscFunctionBeginHot; 3939 if (ornt) { 3940 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3941 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; 3942 } 3943 if (*points) { 3944 closure = *points; 3945 } else { 3946 PetscInt maxConeSize, maxSupportSize; 3947 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3948 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3949 } 3950 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3951 if (ct == DM_POLYTOPE_UNKNOWN) { 3952 closure[off++] = p; 3953 closure[off++] = 0; 3954 for (t = 0; t < tmpSize; ++t) { 3955 closure[off++] = tmp[t]; 3956 closure[off++] = tmpO ? tmpO[t] : 0; 3957 } 3958 } else { 3959 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3960 3961 /* We assume that cells with a valid type have faces with a valid type */ 3962 closure[off++] = p; 3963 closure[off++] = ornt; 3964 for (t = 0; t < tmpSize; ++t) { 3965 DMPolytopeType ft; 3966 3967 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3968 closure[off++] = tmp[arr[t]]; 3969 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3970 } 3971 } 3972 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3973 if (numPoints) *numPoints = tmpSize + 1; 3974 if (points) *points = closure; 3975 PetscFunctionReturn(PETSC_SUCCESS); 3976 } 3977 3978 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3979 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3980 { 3981 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3982 const PetscInt *cone, *ornt; 3983 PetscInt *pts, *closure = NULL; 3984 DMPolytopeType ft; 3985 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3986 PetscInt dim, coneSize, c, d, clSize, cl; 3987 3988 PetscFunctionBeginHot; 3989 PetscCall(DMGetDimension(dm, &dim)); 3990 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3991 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3992 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3993 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3994 maxSize = PetscMax(coneSeries, supportSeries); 3995 if (*points) { 3996 pts = *points; 3997 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3998 c = 0; 3999 pts[c++] = point; 4000 pts[c++] = o; 4001 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4002 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4003 for (cl = 0; cl < clSize * 2; cl += 2) { 4004 pts[c++] = closure[cl]; 4005 pts[c++] = closure[cl + 1]; 4006 } 4007 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4008 for (cl = 0; cl < clSize * 2; cl += 2) { 4009 pts[c++] = closure[cl]; 4010 pts[c++] = closure[cl + 1]; 4011 } 4012 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4013 for (d = 2; d < coneSize; ++d) { 4014 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4015 pts[c++] = cone[arr[d * 2 + 0]]; 4016 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4017 } 4018 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4019 if (dim >= 3) { 4020 for (d = 2; d < coneSize; ++d) { 4021 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4022 const PetscInt *fcone, *fornt; 4023 PetscInt fconeSize, fc, i; 4024 4025 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4026 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4027 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4028 for (fc = 0; fc < fconeSize; ++fc) { 4029 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4030 const PetscInt co = farr[fc * 2 + 1]; 4031 4032 for (i = 0; i < c; i += 2) 4033 if (pts[i] == cp) break; 4034 if (i == c) { 4035 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4036 pts[c++] = cp; 4037 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4038 } 4039 } 4040 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4041 } 4042 } 4043 *numPoints = c / 2; 4044 *points = pts; 4045 PetscFunctionReturn(PETSC_SUCCESS); 4046 } 4047 4048 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4049 { 4050 DMPolytopeType ct; 4051 PetscInt *closure, *fifo; 4052 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4053 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4054 PetscInt depth, maxSize; 4055 4056 PetscFunctionBeginHot; 4057 PetscCall(DMPlexGetDepth(dm, &depth)); 4058 if (depth == 1) { 4059 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4060 PetscFunctionReturn(PETSC_SUCCESS); 4061 } 4062 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4063 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; 4064 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4065 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4066 PetscFunctionReturn(PETSC_SUCCESS); 4067 } 4068 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4069 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4070 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4071 maxSize = PetscMax(coneSeries, supportSeries); 4072 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4073 if (*points) { 4074 closure = *points; 4075 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4076 closure[closureSize++] = p; 4077 closure[closureSize++] = ornt; 4078 fifo[fifoSize++] = p; 4079 fifo[fifoSize++] = ornt; 4080 fifo[fifoSize++] = ct; 4081 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4082 while (fifoSize - fifoStart) { 4083 const PetscInt q = fifo[fifoStart++]; 4084 const PetscInt o = fifo[fifoStart++]; 4085 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4086 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4087 const PetscInt *tmp, *tmpO = NULL; 4088 PetscInt tmpSize, t; 4089 4090 if (PetscDefined(USE_DEBUG)) { 4091 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4092 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); 4093 } 4094 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4095 for (t = 0; t < tmpSize; ++t) { 4096 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4097 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4098 const PetscInt cp = tmp[ip]; 4099 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4100 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4101 PetscInt c; 4102 4103 /* Check for duplicate */ 4104 for (c = 0; c < closureSize; c += 2) { 4105 if (closure[c] == cp) break; 4106 } 4107 if (c == closureSize) { 4108 closure[closureSize++] = cp; 4109 closure[closureSize++] = co; 4110 fifo[fifoSize++] = cp; 4111 fifo[fifoSize++] = co; 4112 fifo[fifoSize++] = ct; 4113 } 4114 } 4115 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4116 } 4117 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4118 if (numPoints) *numPoints = closureSize / 2; 4119 if (points) *points = closure; 4120 PetscFunctionReturn(PETSC_SUCCESS); 4121 } 4122 4123 /*@C 4124 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4125 4126 Not Collective 4127 4128 Input Parameters: 4129 + dm - The `DMPLEX` 4130 . p - The mesh point 4131 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4132 4133 Input/Output Parameter: 4134 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4135 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4136 otherwise the provided array is used to hold the values 4137 4138 Output Parameter: 4139 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4140 4141 Level: beginner 4142 4143 Note: 4144 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4145 4146 Fortran Notes: 4147 `points` must be declared with 4148 .vb 4149 PetscInt, pointer :: points(:) 4150 .ve 4151 and is always allocated by the function. 4152 4153 The `numPoints` argument is not present in the Fortran binding. 4154 4155 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4156 @*/ 4157 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4158 { 4159 PetscFunctionBeginHot; 4160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4161 if (numPoints) PetscAssertPointer(numPoints, 4); 4162 if (points) PetscAssertPointer(points, 5); 4163 if (PetscDefined(USE_DEBUG)) { 4164 PetscInt pStart, pEnd; 4165 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4166 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); 4167 } 4168 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4169 PetscFunctionReturn(PETSC_SUCCESS); 4170 } 4171 4172 /*@C 4173 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4174 4175 Not Collective 4176 4177 Input Parameters: 4178 + dm - The `DMPLEX` 4179 . p - The mesh point 4180 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4181 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4182 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4183 4184 Level: beginner 4185 4186 Note: 4187 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4188 4189 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4190 @*/ 4191 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4192 { 4193 PetscFunctionBeginHot; 4194 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4195 if (numPoints) *numPoints = 0; 4196 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4197 PetscFunctionReturn(PETSC_SUCCESS); 4198 } 4199 4200 /*@ 4201 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4202 4203 Not Collective 4204 4205 Input Parameter: 4206 . dm - The `DMPLEX` 4207 4208 Output Parameters: 4209 + maxConeSize - The maximum number of in-edges 4210 - maxSupportSize - The maximum number of out-edges 4211 4212 Level: beginner 4213 4214 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4215 @*/ 4216 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4217 { 4218 DM_Plex *mesh = (DM_Plex *)dm->data; 4219 4220 PetscFunctionBegin; 4221 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4222 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4223 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4224 PetscFunctionReturn(PETSC_SUCCESS); 4225 } 4226 4227 PetscErrorCode DMSetUp_Plex(DM dm) 4228 { 4229 DM_Plex *mesh = (DM_Plex *)dm->data; 4230 PetscInt size, maxSupportSize; 4231 4232 PetscFunctionBegin; 4233 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4234 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4235 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4236 PetscCall(PetscMalloc1(size, &mesh->cones)); 4237 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4238 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4239 if (maxSupportSize) { 4240 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4241 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4242 PetscCall(PetscMalloc1(size, &mesh->supports)); 4243 } 4244 PetscFunctionReturn(PETSC_SUCCESS); 4245 } 4246 4247 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4248 { 4249 PetscFunctionBegin; 4250 if (subdm) PetscCall(DMClone(dm, subdm)); 4251 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4252 if (subdm) (*subdm)->useNatural = dm->useNatural; 4253 if (dm->useNatural && dm->sfMigration) { 4254 PetscSF sfNatural; 4255 4256 (*subdm)->sfMigration = dm->sfMigration; 4257 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4258 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4259 (*subdm)->sfNatural = sfNatural; 4260 } 4261 PetscFunctionReturn(PETSC_SUCCESS); 4262 } 4263 4264 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4265 { 4266 PetscInt i = 0; 4267 4268 PetscFunctionBegin; 4269 PetscCall(DMClone(dms[0], superdm)); 4270 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4271 (*superdm)->useNatural = PETSC_FALSE; 4272 for (i = 0; i < len; i++) { 4273 if (dms[i]->useNatural && dms[i]->sfMigration) { 4274 PetscSF sfNatural; 4275 4276 (*superdm)->sfMigration = dms[i]->sfMigration; 4277 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4278 (*superdm)->useNatural = PETSC_TRUE; 4279 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4280 (*superdm)->sfNatural = sfNatural; 4281 break; 4282 } 4283 } 4284 PetscFunctionReturn(PETSC_SUCCESS); 4285 } 4286 4287 /*@ 4288 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4289 4290 Not Collective 4291 4292 Input Parameter: 4293 . dm - The `DMPLEX` 4294 4295 Level: beginner 4296 4297 Note: 4298 This should be called after all calls to `DMPlexSetCone()` 4299 4300 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4301 @*/ 4302 PetscErrorCode DMPlexSymmetrize(DM dm) 4303 { 4304 DM_Plex *mesh = (DM_Plex *)dm->data; 4305 PetscInt *offsets; 4306 PetscInt supportSize; 4307 PetscInt pStart, pEnd, p; 4308 4309 PetscFunctionBegin; 4310 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4311 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4312 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4313 /* Calculate support sizes */ 4314 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4315 for (p = pStart; p < pEnd; ++p) { 4316 PetscInt dof, off, c; 4317 4318 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4319 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4320 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4321 } 4322 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4323 /* Calculate supports */ 4324 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4325 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4326 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4327 for (p = pStart; p < pEnd; ++p) { 4328 PetscInt dof, off, c; 4329 4330 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4331 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4332 for (c = off; c < off + dof; ++c) { 4333 const PetscInt q = mesh->cones[c]; 4334 PetscInt offS; 4335 4336 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4337 4338 mesh->supports[offS + offsets[q]] = p; 4339 ++offsets[q]; 4340 } 4341 } 4342 PetscCall(PetscFree(offsets)); 4343 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4344 PetscFunctionReturn(PETSC_SUCCESS); 4345 } 4346 4347 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4348 { 4349 IS stratumIS; 4350 4351 PetscFunctionBegin; 4352 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4353 if (PetscDefined(USE_DEBUG)) { 4354 PetscInt qStart, qEnd, numLevels, level; 4355 PetscBool overlap = PETSC_FALSE; 4356 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4357 for (level = 0; level < numLevels; level++) { 4358 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4359 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4360 overlap = PETSC_TRUE; 4361 break; 4362 } 4363 } 4364 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); 4365 } 4366 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4367 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4368 PetscCall(ISDestroy(&stratumIS)); 4369 PetscFunctionReturn(PETSC_SUCCESS); 4370 } 4371 4372 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4373 { 4374 PetscInt *pMin, *pMax; 4375 PetscInt pStart, pEnd; 4376 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4377 4378 PetscFunctionBegin; 4379 { 4380 DMLabel label2; 4381 4382 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4383 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4384 } 4385 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4386 for (PetscInt p = pStart; p < pEnd; ++p) { 4387 DMPolytopeType ct; 4388 4389 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4390 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4391 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4392 } 4393 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4394 for (PetscInt d = dmin; d <= dmax; ++d) { 4395 pMin[d] = PETSC_MAX_INT; 4396 pMax[d] = PETSC_MIN_INT; 4397 } 4398 for (PetscInt p = pStart; p < pEnd; ++p) { 4399 DMPolytopeType ct; 4400 PetscInt d; 4401 4402 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4403 d = DMPolytopeTypeGetDim(ct); 4404 pMin[d] = PetscMin(p, pMin[d]); 4405 pMax[d] = PetscMax(p, pMax[d]); 4406 } 4407 for (PetscInt d = dmin; d <= dmax; ++d) { 4408 if (pMin[d] > pMax[d]) continue; 4409 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4410 } 4411 PetscCall(PetscFree2(pMin, pMax)); 4412 PetscFunctionReturn(PETSC_SUCCESS); 4413 } 4414 4415 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4416 { 4417 PetscInt pStart, pEnd; 4418 PetscInt numRoots = 0, numLeaves = 0; 4419 4420 PetscFunctionBegin; 4421 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4422 { 4423 /* Initialize roots and count leaves */ 4424 PetscInt sMin = PETSC_MAX_INT; 4425 PetscInt sMax = PETSC_MIN_INT; 4426 PetscInt coneSize, supportSize; 4427 4428 for (PetscInt p = pStart; p < pEnd; ++p) { 4429 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4430 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4431 if (!coneSize && supportSize) { 4432 sMin = PetscMin(p, sMin); 4433 sMax = PetscMax(p, sMax); 4434 ++numRoots; 4435 } else if (!supportSize && coneSize) { 4436 ++numLeaves; 4437 } else if (!supportSize && !coneSize) { 4438 /* Isolated points */ 4439 sMin = PetscMin(p, sMin); 4440 sMax = PetscMax(p, sMax); 4441 } 4442 } 4443 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4444 } 4445 4446 if (numRoots + numLeaves == (pEnd - pStart)) { 4447 PetscInt sMin = PETSC_MAX_INT; 4448 PetscInt sMax = PETSC_MIN_INT; 4449 PetscInt coneSize, supportSize; 4450 4451 for (PetscInt p = pStart; p < pEnd; ++p) { 4452 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4453 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4454 if (!supportSize && coneSize) { 4455 sMin = PetscMin(p, sMin); 4456 sMax = PetscMax(p, sMax); 4457 } 4458 } 4459 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4460 } else { 4461 PetscInt level = 0; 4462 PetscInt qStart, qEnd; 4463 4464 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4465 while (qEnd > qStart) { 4466 PetscInt sMin = PETSC_MAX_INT; 4467 PetscInt sMax = PETSC_MIN_INT; 4468 4469 for (PetscInt q = qStart; q < qEnd; ++q) { 4470 const PetscInt *support; 4471 PetscInt supportSize; 4472 4473 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4474 PetscCall(DMPlexGetSupport(dm, q, &support)); 4475 for (PetscInt s = 0; s < supportSize; ++s) { 4476 sMin = PetscMin(support[s], sMin); 4477 sMax = PetscMax(support[s], sMax); 4478 } 4479 } 4480 PetscCall(DMLabelGetNumValues(label, &level)); 4481 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4482 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4483 } 4484 } 4485 PetscFunctionReturn(PETSC_SUCCESS); 4486 } 4487 4488 /*@ 4489 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4490 4491 Collective 4492 4493 Input Parameter: 4494 . dm - The `DMPLEX` 4495 4496 Level: beginner 4497 4498 Notes: 4499 The strata group all points of the same grade, and this function calculates the strata. This 4500 grade can be seen as the height (or depth) of the point in the DAG. 4501 4502 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4503 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4504 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4505 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4506 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4507 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4508 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4509 4510 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4511 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4512 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 4513 to interpolate only that one (e0), so that 4514 .vb 4515 cone(c0) = {e0, v2} 4516 cone(e0) = {v0, v1} 4517 .ve 4518 If `DMPlexStratify()` is run on this mesh, it will give depths 4519 .vb 4520 depth 0 = {v0, v1, v2} 4521 depth 1 = {e0, c0} 4522 .ve 4523 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4524 4525 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4526 4527 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4528 @*/ 4529 PetscErrorCode DMPlexStratify(DM dm) 4530 { 4531 DM_Plex *mesh = (DM_Plex *)dm->data; 4532 DMLabel label; 4533 PetscBool flg = PETSC_FALSE; 4534 4535 PetscFunctionBegin; 4536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4537 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4538 4539 // Create depth label 4540 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4541 PetscCall(DMCreateLabel(dm, "depth")); 4542 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4543 4544 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4545 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4546 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4547 4548 { /* just in case there is an empty process */ 4549 PetscInt numValues, maxValues = 0, v; 4550 4551 PetscCall(DMLabelGetNumValues(label, &numValues)); 4552 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4553 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4554 } 4555 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4556 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4557 PetscFunctionReturn(PETSC_SUCCESS); 4558 } 4559 4560 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4561 { 4562 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4563 PetscInt dim, depth, pheight, coneSize; 4564 4565 PetscFunctionBeginHot; 4566 PetscCall(DMGetDimension(dm, &dim)); 4567 PetscCall(DMPlexGetDepth(dm, &depth)); 4568 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4569 pheight = depth - pdepth; 4570 if (depth <= 1) { 4571 switch (pdepth) { 4572 case 0: 4573 ct = DM_POLYTOPE_POINT; 4574 break; 4575 case 1: 4576 switch (coneSize) { 4577 case 2: 4578 ct = DM_POLYTOPE_SEGMENT; 4579 break; 4580 case 3: 4581 ct = DM_POLYTOPE_TRIANGLE; 4582 break; 4583 case 4: 4584 switch (dim) { 4585 case 2: 4586 ct = DM_POLYTOPE_QUADRILATERAL; 4587 break; 4588 case 3: 4589 ct = DM_POLYTOPE_TETRAHEDRON; 4590 break; 4591 default: 4592 break; 4593 } 4594 break; 4595 case 5: 4596 ct = DM_POLYTOPE_PYRAMID; 4597 break; 4598 case 6: 4599 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4600 break; 4601 case 8: 4602 ct = DM_POLYTOPE_HEXAHEDRON; 4603 break; 4604 default: 4605 break; 4606 } 4607 } 4608 } else { 4609 if (pdepth == 0) { 4610 ct = DM_POLYTOPE_POINT; 4611 } else if (pheight == 0) { 4612 switch (dim) { 4613 case 1: 4614 switch (coneSize) { 4615 case 2: 4616 ct = DM_POLYTOPE_SEGMENT; 4617 break; 4618 default: 4619 break; 4620 } 4621 break; 4622 case 2: 4623 switch (coneSize) { 4624 case 3: 4625 ct = DM_POLYTOPE_TRIANGLE; 4626 break; 4627 case 4: 4628 ct = DM_POLYTOPE_QUADRILATERAL; 4629 break; 4630 default: 4631 break; 4632 } 4633 break; 4634 case 3: 4635 switch (coneSize) { 4636 case 4: 4637 ct = DM_POLYTOPE_TETRAHEDRON; 4638 break; 4639 case 5: { 4640 const PetscInt *cone; 4641 PetscInt faceConeSize; 4642 4643 PetscCall(DMPlexGetCone(dm, p, &cone)); 4644 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4645 switch (faceConeSize) { 4646 case 3: 4647 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4648 break; 4649 case 4: 4650 ct = DM_POLYTOPE_PYRAMID; 4651 break; 4652 } 4653 } break; 4654 case 6: 4655 ct = DM_POLYTOPE_HEXAHEDRON; 4656 break; 4657 default: 4658 break; 4659 } 4660 break; 4661 default: 4662 break; 4663 } 4664 } else if (pheight > 0) { 4665 switch (coneSize) { 4666 case 2: 4667 ct = DM_POLYTOPE_SEGMENT; 4668 break; 4669 case 3: 4670 ct = DM_POLYTOPE_TRIANGLE; 4671 break; 4672 case 4: 4673 ct = DM_POLYTOPE_QUADRILATERAL; 4674 break; 4675 default: 4676 break; 4677 } 4678 } 4679 } 4680 *pt = ct; 4681 PetscFunctionReturn(PETSC_SUCCESS); 4682 } 4683 4684 /*@ 4685 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4686 4687 Collective 4688 4689 Input Parameter: 4690 . dm - The `DMPLEX` 4691 4692 Level: developer 4693 4694 Note: 4695 This function is normally called automatically when a cell type is requested. It creates an 4696 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4697 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4698 4699 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4700 4701 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4702 @*/ 4703 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4704 { 4705 DM_Plex *mesh; 4706 DMLabel ctLabel; 4707 PetscInt pStart, pEnd, p; 4708 4709 PetscFunctionBegin; 4710 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4711 mesh = (DM_Plex *)dm->data; 4712 PetscCall(DMCreateLabel(dm, "celltype")); 4713 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4714 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4715 PetscCall(PetscFree(mesh->cellTypes)); 4716 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4717 for (p = pStart; p < pEnd; ++p) { 4718 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4719 PetscInt pdepth; 4720 4721 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4722 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4723 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]); 4724 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4725 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4726 } 4727 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4728 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4729 PetscFunctionReturn(PETSC_SUCCESS); 4730 } 4731 4732 /*@C 4733 DMPlexGetJoin - Get an array for the join of the set of points 4734 4735 Not Collective 4736 4737 Input Parameters: 4738 + dm - The `DMPLEX` object 4739 . numPoints - The number of input points for the join 4740 - points - The input points 4741 4742 Output Parameters: 4743 + numCoveredPoints - The number of points in the join 4744 - coveredPoints - The points in the join 4745 4746 Level: intermediate 4747 4748 Note: 4749 Currently, this is restricted to a single level join 4750 4751 Fortran Notes: 4752 `converedPoints` must be declared with 4753 .vb 4754 PetscInt, pointer :: coveredPints(:) 4755 .ve 4756 4757 The `numCoveredPoints` argument is not present in the Fortran binding. 4758 4759 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4760 @*/ 4761 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4762 { 4763 DM_Plex *mesh = (DM_Plex *)dm->data; 4764 PetscInt *join[2]; 4765 PetscInt joinSize, i = 0; 4766 PetscInt dof, off, p, c, m; 4767 PetscInt maxSupportSize; 4768 4769 PetscFunctionBegin; 4770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4771 PetscAssertPointer(points, 3); 4772 PetscAssertPointer(numCoveredPoints, 4); 4773 PetscAssertPointer(coveredPoints, 5); 4774 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4775 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4776 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4777 /* Copy in support of first point */ 4778 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4779 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4780 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4781 /* Check each successive support */ 4782 for (p = 1; p < numPoints; ++p) { 4783 PetscInt newJoinSize = 0; 4784 4785 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4786 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4787 for (c = 0; c < dof; ++c) { 4788 const PetscInt point = mesh->supports[off + c]; 4789 4790 for (m = 0; m < joinSize; ++m) { 4791 if (point == join[i][m]) { 4792 join[1 - i][newJoinSize++] = point; 4793 break; 4794 } 4795 } 4796 } 4797 joinSize = newJoinSize; 4798 i = 1 - i; 4799 } 4800 *numCoveredPoints = joinSize; 4801 *coveredPoints = join[i]; 4802 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4803 PetscFunctionReturn(PETSC_SUCCESS); 4804 } 4805 4806 /*@C 4807 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4808 4809 Not Collective 4810 4811 Input Parameters: 4812 + dm - The `DMPLEX` object 4813 . numPoints - The number of input points for the join 4814 - points - The input points 4815 4816 Output Parameters: 4817 + numCoveredPoints - The number of points in the join 4818 - coveredPoints - The points in the join 4819 4820 Level: intermediate 4821 4822 Fortran Notes: 4823 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4824 4825 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4826 @*/ 4827 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4828 { 4829 PetscFunctionBegin; 4830 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4831 if (points) PetscAssertPointer(points, 3); 4832 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4833 PetscAssertPointer(coveredPoints, 5); 4834 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4835 if (numCoveredPoints) *numCoveredPoints = 0; 4836 PetscFunctionReturn(PETSC_SUCCESS); 4837 } 4838 4839 /*@C 4840 DMPlexGetFullJoin - Get an array for the join of the set of points 4841 4842 Not Collective 4843 4844 Input Parameters: 4845 + dm - The `DMPLEX` object 4846 . numPoints - The number of input points for the join 4847 - points - The input points, its length is `numPoints` 4848 4849 Output Parameters: 4850 + numCoveredPoints - The number of points in the join 4851 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4852 4853 Level: intermediate 4854 4855 Fortran Notes: 4856 `points` and `converedPoints` must be declared with 4857 .vb 4858 PetscInt, pointer :: points(:) 4859 PetscInt, pointer :: coveredPints(:) 4860 .ve 4861 4862 The `numCoveredPoints` argument is not present in the Fortran binding. 4863 4864 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4865 @*/ 4866 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4867 { 4868 PetscInt *offsets, **closures; 4869 PetscInt *join[2]; 4870 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4871 PetscInt p, d, c, m, ms; 4872 4873 PetscFunctionBegin; 4874 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4875 PetscAssertPointer(points, 3); 4876 PetscAssertPointer(numCoveredPoints, 4); 4877 PetscAssertPointer(coveredPoints, 5); 4878 4879 PetscCall(DMPlexGetDepth(dm, &depth)); 4880 PetscCall(PetscCalloc1(numPoints, &closures)); 4881 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4882 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4883 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4884 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4885 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4886 4887 for (p = 0; p < numPoints; ++p) { 4888 PetscInt closureSize; 4889 4890 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4891 4892 offsets[p * (depth + 2) + 0] = 0; 4893 for (d = 0; d < depth + 1; ++d) { 4894 PetscInt pStart, pEnd, i; 4895 4896 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4897 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4898 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4899 offsets[p * (depth + 2) + d + 1] = i; 4900 break; 4901 } 4902 } 4903 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4904 } 4905 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); 4906 } 4907 for (d = 0; d < depth + 1; ++d) { 4908 PetscInt dof; 4909 4910 /* Copy in support of first point */ 4911 dof = offsets[d + 1] - offsets[d]; 4912 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4913 /* Check each successive cone */ 4914 for (p = 1; p < numPoints && joinSize; ++p) { 4915 PetscInt newJoinSize = 0; 4916 4917 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4918 for (c = 0; c < dof; ++c) { 4919 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4920 4921 for (m = 0; m < joinSize; ++m) { 4922 if (point == join[i][m]) { 4923 join[1 - i][newJoinSize++] = point; 4924 break; 4925 } 4926 } 4927 } 4928 joinSize = newJoinSize; 4929 i = 1 - i; 4930 } 4931 if (joinSize) break; 4932 } 4933 *numCoveredPoints = joinSize; 4934 *coveredPoints = join[i]; 4935 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4936 PetscCall(PetscFree(closures)); 4937 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4938 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4939 PetscFunctionReturn(PETSC_SUCCESS); 4940 } 4941 4942 /*@C 4943 DMPlexGetMeet - Get an array for the meet of the set of points 4944 4945 Not Collective 4946 4947 Input Parameters: 4948 + dm - The `DMPLEX` object 4949 . numPoints - The number of input points for the meet 4950 - points - The input points, of length `numPoints` 4951 4952 Output Parameters: 4953 + numCoveringPoints - The number of points in the meet 4954 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4955 4956 Level: intermediate 4957 4958 Note: 4959 Currently, this is restricted to a single level meet 4960 4961 Fortran Notes: 4962 `coveringPoints` must be declared with 4963 .vb 4964 PetscInt, pointer :: coveringPoints(:) 4965 .ve 4966 4967 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4968 4969 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4970 @*/ 4971 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4972 { 4973 DM_Plex *mesh = (DM_Plex *)dm->data; 4974 PetscInt *meet[2]; 4975 PetscInt meetSize, i = 0; 4976 PetscInt dof, off, p, c, m; 4977 PetscInt maxConeSize; 4978 4979 PetscFunctionBegin; 4980 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4981 PetscAssertPointer(points, 3); 4982 PetscAssertPointer(numCoveringPoints, 4); 4983 PetscAssertPointer(coveringPoints, 5); 4984 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4985 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4986 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4987 /* Copy in cone of first point */ 4988 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4989 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4990 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4991 /* Check each successive cone */ 4992 for (p = 1; p < numPoints; ++p) { 4993 PetscInt newMeetSize = 0; 4994 4995 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4996 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4997 for (c = 0; c < dof; ++c) { 4998 const PetscInt point = mesh->cones[off + c]; 4999 5000 for (m = 0; m < meetSize; ++m) { 5001 if (point == meet[i][m]) { 5002 meet[1 - i][newMeetSize++] = point; 5003 break; 5004 } 5005 } 5006 } 5007 meetSize = newMeetSize; 5008 i = 1 - i; 5009 } 5010 *numCoveringPoints = meetSize; 5011 *coveringPoints = meet[i]; 5012 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5013 PetscFunctionReturn(PETSC_SUCCESS); 5014 } 5015 5016 /*@C 5017 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5018 5019 Not Collective 5020 5021 Input Parameters: 5022 + dm - The `DMPLEX` object 5023 . numPoints - The number of input points for the meet 5024 - points - The input points 5025 5026 Output Parameters: 5027 + numCoveredPoints - The number of points in the meet 5028 - coveredPoints - The points in the meet 5029 5030 Level: intermediate 5031 5032 Fortran Notes: 5033 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5034 5035 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5036 @*/ 5037 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5038 { 5039 PetscFunctionBegin; 5040 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5041 if (points) PetscAssertPointer(points, 3); 5042 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5043 PetscAssertPointer(coveredPoints, 5); 5044 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5045 if (numCoveredPoints) *numCoveredPoints = 0; 5046 PetscFunctionReturn(PETSC_SUCCESS); 5047 } 5048 5049 /*@C 5050 DMPlexGetFullMeet - Get an array for the meet of the set of points 5051 5052 Not Collective 5053 5054 Input Parameters: 5055 + dm - The `DMPLEX` object 5056 . numPoints - The number of input points for the meet 5057 - points - The input points, of length `numPoints` 5058 5059 Output Parameters: 5060 + numCoveredPoints - The number of points in the meet 5061 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5062 5063 Level: intermediate 5064 5065 Fortran Notes: 5066 `points` and `coveredPoints` must be declared with 5067 .vb 5068 PetscInt, pointer :: points(:) 5069 PetscInt, pointer :: coveredPoints(:) 5070 .ve 5071 5072 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5073 5074 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5075 @*/ 5076 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5077 { 5078 PetscInt *offsets, **closures; 5079 PetscInt *meet[2]; 5080 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5081 PetscInt p, h, c, m, mc; 5082 5083 PetscFunctionBegin; 5084 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5085 PetscAssertPointer(points, 3); 5086 PetscAssertPointer(numCoveredPoints, 4); 5087 PetscAssertPointer(coveredPoints, 5); 5088 5089 PetscCall(DMPlexGetDepth(dm, &height)); 5090 PetscCall(PetscMalloc1(numPoints, &closures)); 5091 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5092 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5093 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5094 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5095 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5096 5097 for (p = 0; p < numPoints; ++p) { 5098 PetscInt closureSize; 5099 5100 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5101 5102 offsets[p * (height + 2) + 0] = 0; 5103 for (h = 0; h < height + 1; ++h) { 5104 PetscInt pStart, pEnd, i; 5105 5106 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5107 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5108 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5109 offsets[p * (height + 2) + h + 1] = i; 5110 break; 5111 } 5112 } 5113 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5114 } 5115 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); 5116 } 5117 for (h = 0; h < height + 1; ++h) { 5118 PetscInt dof; 5119 5120 /* Copy in cone of first point */ 5121 dof = offsets[h + 1] - offsets[h]; 5122 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5123 /* Check each successive cone */ 5124 for (p = 1; p < numPoints && meetSize; ++p) { 5125 PetscInt newMeetSize = 0; 5126 5127 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5128 for (c = 0; c < dof; ++c) { 5129 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5130 5131 for (m = 0; m < meetSize; ++m) { 5132 if (point == meet[i][m]) { 5133 meet[1 - i][newMeetSize++] = point; 5134 break; 5135 } 5136 } 5137 } 5138 meetSize = newMeetSize; 5139 i = 1 - i; 5140 } 5141 if (meetSize) break; 5142 } 5143 *numCoveredPoints = meetSize; 5144 *coveredPoints = meet[i]; 5145 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5146 PetscCall(PetscFree(closures)); 5147 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5148 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5149 PetscFunctionReturn(PETSC_SUCCESS); 5150 } 5151 5152 /*@ 5153 DMPlexEqual - Determine if two `DM` have the same topology 5154 5155 Not Collective 5156 5157 Input Parameters: 5158 + dmA - A `DMPLEX` object 5159 - dmB - A `DMPLEX` object 5160 5161 Output Parameter: 5162 . equal - `PETSC_TRUE` if the topologies are identical 5163 5164 Level: intermediate 5165 5166 Note: 5167 We are not solving graph isomorphism, so we do not permute. 5168 5169 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5170 @*/ 5171 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5172 { 5173 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5174 5175 PetscFunctionBegin; 5176 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5177 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5178 PetscAssertPointer(equal, 3); 5179 5180 *equal = PETSC_FALSE; 5181 PetscCall(DMPlexGetDepth(dmA, &depth)); 5182 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5183 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5184 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5185 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5186 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5187 for (p = pStart; p < pEnd; ++p) { 5188 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5189 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5190 5191 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5192 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5193 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5194 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5195 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5196 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5197 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5198 for (c = 0; c < coneSize; ++c) { 5199 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5200 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5201 } 5202 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5203 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5204 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5205 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5206 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5207 for (s = 0; s < supportSize; ++s) { 5208 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5209 } 5210 } 5211 *equal = PETSC_TRUE; 5212 PetscFunctionReturn(PETSC_SUCCESS); 5213 } 5214 5215 /*@ 5216 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5217 5218 Not Collective 5219 5220 Input Parameters: 5221 + dm - The `DMPLEX` 5222 . cellDim - The cell dimension 5223 - numCorners - The number of vertices on a cell 5224 5225 Output Parameter: 5226 . numFaceVertices - The number of vertices on a face 5227 5228 Level: developer 5229 5230 Note: 5231 Of course this can only work for a restricted set of symmetric shapes 5232 5233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5234 @*/ 5235 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5236 { 5237 MPI_Comm comm; 5238 5239 PetscFunctionBegin; 5240 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5241 PetscAssertPointer(numFaceVertices, 4); 5242 switch (cellDim) { 5243 case 0: 5244 *numFaceVertices = 0; 5245 break; 5246 case 1: 5247 *numFaceVertices = 1; 5248 break; 5249 case 2: 5250 switch (numCorners) { 5251 case 3: /* triangle */ 5252 *numFaceVertices = 2; /* Edge has 2 vertices */ 5253 break; 5254 case 4: /* quadrilateral */ 5255 *numFaceVertices = 2; /* Edge has 2 vertices */ 5256 break; 5257 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5258 *numFaceVertices = 3; /* Edge has 3 vertices */ 5259 break; 5260 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5261 *numFaceVertices = 3; /* Edge has 3 vertices */ 5262 break; 5263 default: 5264 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5265 } 5266 break; 5267 case 3: 5268 switch (numCorners) { 5269 case 4: /* tetradehdron */ 5270 *numFaceVertices = 3; /* Face has 3 vertices */ 5271 break; 5272 case 6: /* tet cohesive cells */ 5273 *numFaceVertices = 4; /* Face has 4 vertices */ 5274 break; 5275 case 8: /* hexahedron */ 5276 *numFaceVertices = 4; /* Face has 4 vertices */ 5277 break; 5278 case 9: /* tet cohesive Lagrange cells */ 5279 *numFaceVertices = 6; /* Face has 6 vertices */ 5280 break; 5281 case 10: /* quadratic tetrahedron */ 5282 *numFaceVertices = 6; /* Face has 6 vertices */ 5283 break; 5284 case 12: /* hex cohesive Lagrange cells */ 5285 *numFaceVertices = 6; /* Face has 6 vertices */ 5286 break; 5287 case 18: /* quadratic tet cohesive Lagrange cells */ 5288 *numFaceVertices = 6; /* Face has 6 vertices */ 5289 break; 5290 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5291 *numFaceVertices = 9; /* Face has 9 vertices */ 5292 break; 5293 default: 5294 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5295 } 5296 break; 5297 default: 5298 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5299 } 5300 PetscFunctionReturn(PETSC_SUCCESS); 5301 } 5302 5303 /*@ 5304 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5305 5306 Not Collective 5307 5308 Input Parameter: 5309 . dm - The `DMPLEX` object 5310 5311 Output Parameter: 5312 . depthLabel - The `DMLabel` recording point depth 5313 5314 Level: developer 5315 5316 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5317 @*/ 5318 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5319 { 5320 PetscFunctionBegin; 5321 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5322 PetscAssertPointer(depthLabel, 2); 5323 *depthLabel = dm->depthLabel; 5324 PetscFunctionReturn(PETSC_SUCCESS); 5325 } 5326 5327 /*@ 5328 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5329 5330 Not Collective 5331 5332 Input Parameter: 5333 . dm - The `DMPLEX` object 5334 5335 Output Parameter: 5336 . depth - The number of strata (breadth first levels) in the DAG 5337 5338 Level: developer 5339 5340 Notes: 5341 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5342 5343 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5344 5345 An empty mesh gives -1. 5346 5347 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5348 @*/ 5349 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5350 { 5351 DM_Plex *mesh = (DM_Plex *)dm->data; 5352 DMLabel label; 5353 PetscInt d = -1; 5354 5355 PetscFunctionBegin; 5356 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5357 PetscAssertPointer(depth, 2); 5358 if (mesh->tr) { 5359 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5360 } else { 5361 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5362 // Allow missing depths 5363 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5364 *depth = d; 5365 } 5366 PetscFunctionReturn(PETSC_SUCCESS); 5367 } 5368 5369 /*@ 5370 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5371 5372 Not Collective 5373 5374 Input Parameters: 5375 + dm - The `DMPLEX` object 5376 - depth - The requested depth 5377 5378 Output Parameters: 5379 + start - The first point at this `depth` 5380 - end - One beyond the last point at this `depth` 5381 5382 Level: developer 5383 5384 Notes: 5385 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5386 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5387 higher dimension, e.g., "edges". 5388 5389 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5390 @*/ 5391 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5392 { 5393 DM_Plex *mesh = (DM_Plex *)dm->data; 5394 DMLabel label; 5395 PetscInt pStart, pEnd; 5396 5397 PetscFunctionBegin; 5398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5399 if (start) { 5400 PetscAssertPointer(start, 3); 5401 *start = 0; 5402 } 5403 if (end) { 5404 PetscAssertPointer(end, 4); 5405 *end = 0; 5406 } 5407 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5408 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5409 if (depth < 0) { 5410 if (start) *start = pStart; 5411 if (end) *end = pEnd; 5412 PetscFunctionReturn(PETSC_SUCCESS); 5413 } 5414 if (mesh->tr) { 5415 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5416 } else { 5417 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5418 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5419 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5420 } 5421 PetscFunctionReturn(PETSC_SUCCESS); 5422 } 5423 5424 /*@ 5425 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5426 5427 Not Collective 5428 5429 Input Parameters: 5430 + dm - The `DMPLEX` object 5431 - height - The requested height 5432 5433 Output Parameters: 5434 + start - The first point at this `height` 5435 - end - One beyond the last point at this `height` 5436 5437 Level: developer 5438 5439 Notes: 5440 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5441 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5442 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5443 5444 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5445 @*/ 5446 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5447 { 5448 DMLabel label; 5449 PetscInt depth, pStart, pEnd; 5450 5451 PetscFunctionBegin; 5452 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5453 if (start) { 5454 PetscAssertPointer(start, 3); 5455 *start = 0; 5456 } 5457 if (end) { 5458 PetscAssertPointer(end, 4); 5459 *end = 0; 5460 } 5461 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5462 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5463 if (height < 0) { 5464 if (start) *start = pStart; 5465 if (end) *end = pEnd; 5466 PetscFunctionReturn(PETSC_SUCCESS); 5467 } 5468 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5469 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5470 else PetscCall(DMGetDimension(dm, &depth)); 5471 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5472 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5473 PetscFunctionReturn(PETSC_SUCCESS); 5474 } 5475 5476 /*@ 5477 DMPlexGetPointDepth - Get the `depth` of a given point 5478 5479 Not Collective 5480 5481 Input Parameters: 5482 + dm - The `DMPLEX` object 5483 - point - The point 5484 5485 Output Parameter: 5486 . depth - The depth of the `point` 5487 5488 Level: intermediate 5489 5490 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5491 @*/ 5492 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5493 { 5494 PetscFunctionBegin; 5495 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5496 PetscAssertPointer(depth, 3); 5497 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5498 PetscFunctionReturn(PETSC_SUCCESS); 5499 } 5500 5501 /*@ 5502 DMPlexGetPointHeight - Get the `height` of a given point 5503 5504 Not Collective 5505 5506 Input Parameters: 5507 + dm - The `DMPLEX` object 5508 - point - The point 5509 5510 Output Parameter: 5511 . height - The height of the `point` 5512 5513 Level: intermediate 5514 5515 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5516 @*/ 5517 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5518 { 5519 PetscInt n, pDepth; 5520 5521 PetscFunctionBegin; 5522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5523 PetscAssertPointer(height, 3); 5524 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5525 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5526 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5527 PetscFunctionReturn(PETSC_SUCCESS); 5528 } 5529 5530 /*@ 5531 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5532 5533 Not Collective 5534 5535 Input Parameter: 5536 . dm - The `DMPLEX` object 5537 5538 Output Parameter: 5539 . celltypeLabel - The `DMLabel` recording cell polytope type 5540 5541 Level: developer 5542 5543 Note: 5544 This function will trigger automatica computation of cell types. This can be disabled by calling 5545 `DMCreateLabel`(dm, "celltype") beforehand. 5546 5547 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5548 @*/ 5549 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5550 { 5551 PetscFunctionBegin; 5552 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5553 PetscAssertPointer(celltypeLabel, 2); 5554 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5555 *celltypeLabel = dm->celltypeLabel; 5556 PetscFunctionReturn(PETSC_SUCCESS); 5557 } 5558 5559 /*@ 5560 DMPlexGetCellType - Get the polytope type of a given cell 5561 5562 Not Collective 5563 5564 Input Parameters: 5565 + dm - The `DMPLEX` object 5566 - cell - The cell 5567 5568 Output Parameter: 5569 . celltype - The polytope type of the cell 5570 5571 Level: intermediate 5572 5573 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5574 @*/ 5575 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5576 { 5577 DM_Plex *mesh = (DM_Plex *)dm->data; 5578 DMLabel label; 5579 PetscInt ct; 5580 5581 PetscFunctionBegin; 5582 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5583 PetscAssertPointer(celltype, 3); 5584 if (mesh->tr) { 5585 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5586 } else { 5587 PetscInt pStart, pEnd; 5588 5589 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5590 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5591 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5592 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5593 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5594 for (PetscInt p = pStart; p < pEnd; p++) { 5595 PetscCall(DMLabelGetValue(label, p, &ct)); 5596 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5597 } 5598 } 5599 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5600 if (PetscDefined(USE_DEBUG)) { 5601 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5602 PetscCall(DMLabelGetValue(label, cell, &ct)); 5603 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5604 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5605 } 5606 } 5607 PetscFunctionReturn(PETSC_SUCCESS); 5608 } 5609 5610 /*@ 5611 DMPlexSetCellType - Set the polytope type of a given cell 5612 5613 Not Collective 5614 5615 Input Parameters: 5616 + dm - The `DMPLEX` object 5617 . cell - The cell 5618 - celltype - The polytope type of the cell 5619 5620 Level: advanced 5621 5622 Note: 5623 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5624 is executed. This function will override the computed type. However, if automatic classification will not succeed 5625 and a user wants to manually specify all types, the classification must be disabled by calling 5626 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5627 5628 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5629 @*/ 5630 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5631 { 5632 DM_Plex *mesh = (DM_Plex *)dm->data; 5633 DMLabel label; 5634 PetscInt pStart, pEnd; 5635 5636 PetscFunctionBegin; 5637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5638 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5639 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5640 PetscCall(DMLabelSetValue(label, cell, celltype)); 5641 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5642 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5643 PetscFunctionReturn(PETSC_SUCCESS); 5644 } 5645 5646 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5647 { 5648 PetscSection section; 5649 PetscInt maxHeight; 5650 const char *prefix; 5651 5652 PetscFunctionBegin; 5653 PetscCall(DMClone(dm, cdm)); 5654 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5655 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5656 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5657 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5658 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5659 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5660 PetscCall(DMSetLocalSection(*cdm, section)); 5661 PetscCall(PetscSectionDestroy(§ion)); 5662 5663 PetscCall(DMSetNumFields(*cdm, 1)); 5664 PetscCall(DMCreateDS(*cdm)); 5665 (*cdm)->cloneOpts = PETSC_TRUE; 5666 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5667 PetscFunctionReturn(PETSC_SUCCESS); 5668 } 5669 5670 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5671 { 5672 Vec coordsLocal, cellCoordsLocal; 5673 DM coordsDM, cellCoordsDM; 5674 5675 PetscFunctionBegin; 5676 *field = NULL; 5677 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5678 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5679 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5680 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5681 if (coordsLocal && coordsDM) { 5682 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5683 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5684 } 5685 PetscFunctionReturn(PETSC_SUCCESS); 5686 } 5687 5688 /*@ 5689 DMPlexGetConeSection - Return a section which describes the layout of cone data 5690 5691 Not Collective 5692 5693 Input Parameter: 5694 . dm - The `DMPLEX` object 5695 5696 Output Parameter: 5697 . section - The `PetscSection` object 5698 5699 Level: developer 5700 5701 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5702 @*/ 5703 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5704 { 5705 DM_Plex *mesh = (DM_Plex *)dm->data; 5706 5707 PetscFunctionBegin; 5708 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5709 if (section) *section = mesh->coneSection; 5710 PetscFunctionReturn(PETSC_SUCCESS); 5711 } 5712 5713 /*@ 5714 DMPlexGetSupportSection - Return a section which describes the layout of support data 5715 5716 Not Collective 5717 5718 Input Parameter: 5719 . dm - The `DMPLEX` object 5720 5721 Output Parameter: 5722 . section - The `PetscSection` object 5723 5724 Level: developer 5725 5726 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5727 @*/ 5728 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5729 { 5730 DM_Plex *mesh = (DM_Plex *)dm->data; 5731 5732 PetscFunctionBegin; 5733 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5734 if (section) *section = mesh->supportSection; 5735 PetscFunctionReturn(PETSC_SUCCESS); 5736 } 5737 5738 /*@C 5739 DMPlexGetCones - Return cone data 5740 5741 Not Collective 5742 5743 Input Parameter: 5744 . dm - The `DMPLEX` object 5745 5746 Output Parameter: 5747 . cones - The cone for each point 5748 5749 Level: developer 5750 5751 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5752 @*/ 5753 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5754 { 5755 DM_Plex *mesh = (DM_Plex *)dm->data; 5756 5757 PetscFunctionBegin; 5758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5759 if (cones) *cones = mesh->cones; 5760 PetscFunctionReturn(PETSC_SUCCESS); 5761 } 5762 5763 /*@C 5764 DMPlexGetConeOrientations - Return cone orientation data 5765 5766 Not Collective 5767 5768 Input Parameter: 5769 . dm - The `DMPLEX` object 5770 5771 Output Parameter: 5772 . coneOrientations - The array of cone orientations for all points 5773 5774 Level: developer 5775 5776 Notes: 5777 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5778 as returned by `DMPlexGetConeOrientation()`. 5779 5780 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5781 5782 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5783 @*/ 5784 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5785 { 5786 DM_Plex *mesh = (DM_Plex *)dm->data; 5787 5788 PetscFunctionBegin; 5789 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5790 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5791 PetscFunctionReturn(PETSC_SUCCESS); 5792 } 5793 5794 /******************************** FEM Support **********************************/ 5795 5796 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5797 { 5798 PetscInt depth; 5799 5800 PetscFunctionBegin; 5801 PetscCall(DMPlexGetDepth(plex, &depth)); 5802 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5803 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5804 PetscFunctionReturn(PETSC_SUCCESS); 5805 } 5806 5807 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5808 { 5809 PetscInt depth; 5810 5811 PetscFunctionBegin; 5812 PetscCall(DMPlexGetDepth(plex, &depth)); 5813 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5814 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5815 PetscFunctionReturn(PETSC_SUCCESS); 5816 } 5817 5818 /* 5819 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5820 representing a line in the section. 5821 */ 5822 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5823 { 5824 PetscObject obj; 5825 PetscClassId id; 5826 PetscFE fe = NULL; 5827 5828 PetscFunctionBeginHot; 5829 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5830 PetscCall(DMGetField(dm, field, NULL, &obj)); 5831 PetscCall(PetscObjectGetClassId(obj, &id)); 5832 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5833 5834 if (!fe) { 5835 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5836 /* An order k SEM disc has k-1 dofs on an edge */ 5837 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5838 *k = *k / *Nc + 1; 5839 } else { 5840 PetscInt dual_space_size, dim; 5841 PetscDualSpace dsp; 5842 5843 PetscCall(DMGetDimension(dm, &dim)); 5844 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5845 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5846 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5847 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5848 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5849 } 5850 PetscFunctionReturn(PETSC_SUCCESS); 5851 } 5852 5853 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5854 { 5855 PetscFunctionBeginHot; 5856 if (tensor) { 5857 *dof = PetscPowInt(k + 1, dim); 5858 } else { 5859 switch (dim) { 5860 case 1: 5861 *dof = k + 1; 5862 break; 5863 case 2: 5864 *dof = ((k + 1) * (k + 2)) / 2; 5865 break; 5866 case 3: 5867 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5868 break; 5869 default: 5870 *dof = 0; 5871 } 5872 } 5873 PetscFunctionReturn(PETSC_SUCCESS); 5874 } 5875 5876 /*@ 5877 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5878 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5879 section provided (or the section of the `DM`). 5880 5881 Input Parameters: 5882 + dm - The `DM` 5883 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5884 - section - The `PetscSection` to reorder, or `NULL` for the default section 5885 5886 Example: 5887 A typical interpolated single-quad mesh might order points as 5888 .vb 5889 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5890 5891 v4 -- e6 -- v3 5892 | | 5893 e7 c0 e8 5894 | | 5895 v1 -- e5 -- v2 5896 .ve 5897 5898 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5899 dofs in the order of points, e.g., 5900 .vb 5901 c0 -> [0,1,2,3] 5902 v1 -> [4] 5903 ... 5904 e5 -> [8, 9] 5905 .ve 5906 5907 which corresponds to the dofs 5908 .vb 5909 6 10 11 7 5910 13 2 3 15 5911 12 0 1 14 5912 4 8 9 5 5913 .ve 5914 5915 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5916 .vb 5917 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5918 .ve 5919 5920 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5921 .vb 5922 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5923 .ve 5924 5925 Level: developer 5926 5927 Notes: 5928 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5929 degree of the basis. 5930 5931 This is required to run with libCEED. 5932 5933 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5934 @*/ 5935 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5936 { 5937 DMLabel label; 5938 PetscInt dim, depth = -1, eStart = -1, Nf; 5939 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5940 5941 PetscFunctionBegin; 5942 PetscCall(DMGetDimension(dm, &dim)); 5943 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5944 if (point < 0) { 5945 PetscInt sStart, sEnd; 5946 5947 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5948 point = sEnd - sStart ? sStart : point; 5949 } 5950 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5951 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5952 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5953 if (depth == 1) { 5954 eStart = point; 5955 } else if (depth == dim) { 5956 const PetscInt *cone; 5957 5958 PetscCall(DMPlexGetCone(dm, point, &cone)); 5959 if (dim == 2) eStart = cone[0]; 5960 else if (dim == 3) { 5961 const PetscInt *cone2; 5962 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5963 eStart = cone2[0]; 5964 } 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); 5965 } 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); 5966 5967 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5968 for (PetscInt d = 1; d <= dim; d++) { 5969 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5970 PetscInt *perm; 5971 5972 for (f = 0; f < Nf; ++f) { 5973 PetscInt dof; 5974 5975 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5976 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5977 if (!continuous && d < dim) continue; 5978 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5979 size += dof * Nc; 5980 } 5981 PetscCall(PetscMalloc1(size, &perm)); 5982 for (f = 0; f < Nf; ++f) { 5983 switch (d) { 5984 case 1: 5985 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5986 if (!continuous && d < dim) continue; 5987 /* 5988 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5989 We want [ vtx0; edge of length k-1; vtx1 ] 5990 */ 5991 if (continuous) { 5992 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5993 for (i = 0; i < k - 1; i++) 5994 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5995 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5996 foffset = offset; 5997 } else { 5998 PetscInt dof; 5999 6000 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6001 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6002 foffset = offset; 6003 } 6004 break; 6005 case 2: 6006 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6007 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6008 if (!continuous && d < dim) continue; 6009 /* The SEM order is 6010 6011 v_lb, {e_b}, v_rb, 6012 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6013 v_lt, reverse {e_t}, v_rt 6014 */ 6015 if (continuous) { 6016 const PetscInt of = 0; 6017 const PetscInt oeb = of + PetscSqr(k - 1); 6018 const PetscInt oer = oeb + (k - 1); 6019 const PetscInt oet = oer + (k - 1); 6020 const PetscInt oel = oet + (k - 1); 6021 const PetscInt ovlb = oel + (k - 1); 6022 const PetscInt ovrb = ovlb + 1; 6023 const PetscInt ovrt = ovrb + 1; 6024 const PetscInt ovlt = ovrt + 1; 6025 PetscInt o; 6026 6027 /* bottom */ 6028 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6029 for (o = oeb; o < oer; ++o) 6030 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6031 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6032 /* middle */ 6033 for (i = 0; i < k - 1; ++i) { 6034 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6035 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6036 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6037 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6038 } 6039 /* top */ 6040 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6041 for (o = oel - 1; o >= oet; --o) 6042 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6043 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6044 foffset = offset; 6045 } else { 6046 PetscInt dof; 6047 6048 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6049 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6050 foffset = offset; 6051 } 6052 break; 6053 case 3: 6054 /* The original hex closure is 6055 6056 {c, 6057 f_b, f_t, f_f, f_b, f_r, f_l, 6058 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6059 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6060 */ 6061 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6062 if (!continuous && d < dim) continue; 6063 /* The SEM order is 6064 Bottom Slice 6065 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6066 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6067 v_blb, {e_bb}, v_brb, 6068 6069 Middle Slice (j) 6070 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6071 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6072 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6073 6074 Top Slice 6075 v_tlf, {e_tf}, v_trf, 6076 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6077 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6078 */ 6079 if (continuous) { 6080 const PetscInt oc = 0; 6081 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6082 const PetscInt oft = ofb + PetscSqr(k - 1); 6083 const PetscInt off = oft + PetscSqr(k - 1); 6084 const PetscInt ofk = off + PetscSqr(k - 1); 6085 const PetscInt ofr = ofk + PetscSqr(k - 1); 6086 const PetscInt ofl = ofr + PetscSqr(k - 1); 6087 const PetscInt oebl = ofl + PetscSqr(k - 1); 6088 const PetscInt oebb = oebl + (k - 1); 6089 const PetscInt oebr = oebb + (k - 1); 6090 const PetscInt oebf = oebr + (k - 1); 6091 const PetscInt oetf = oebf + (k - 1); 6092 const PetscInt oetr = oetf + (k - 1); 6093 const PetscInt oetb = oetr + (k - 1); 6094 const PetscInt oetl = oetb + (k - 1); 6095 const PetscInt oerf = oetl + (k - 1); 6096 const PetscInt oelf = oerf + (k - 1); 6097 const PetscInt oelb = oelf + (k - 1); 6098 const PetscInt oerb = oelb + (k - 1); 6099 const PetscInt ovblf = oerb + (k - 1); 6100 const PetscInt ovblb = ovblf + 1; 6101 const PetscInt ovbrb = ovblb + 1; 6102 const PetscInt ovbrf = ovbrb + 1; 6103 const PetscInt ovtlf = ovbrf + 1; 6104 const PetscInt ovtrf = ovtlf + 1; 6105 const PetscInt ovtrb = ovtrf + 1; 6106 const PetscInt ovtlb = ovtrb + 1; 6107 PetscInt o, n; 6108 6109 /* Bottom Slice */ 6110 /* bottom */ 6111 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6112 for (o = oetf - 1; o >= oebf; --o) 6113 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6114 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6115 /* middle */ 6116 for (i = 0; i < k - 1; ++i) { 6117 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6118 for (n = 0; n < k - 1; ++n) { 6119 o = ofb + n * (k - 1) + i; 6120 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6121 } 6122 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6123 } 6124 /* top */ 6125 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6126 for (o = oebb; o < oebr; ++o) 6127 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6128 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6129 6130 /* Middle Slice */ 6131 for (j = 0; j < k - 1; ++j) { 6132 /* bottom */ 6133 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6134 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6135 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6136 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6137 /* middle */ 6138 for (i = 0; i < k - 1; ++i) { 6139 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6140 for (n = 0; n < k - 1; ++n) 6141 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6142 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6143 } 6144 /* top */ 6145 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6146 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6147 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6148 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6149 } 6150 6151 /* Top Slice */ 6152 /* bottom */ 6153 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6154 for (o = oetf; o < oetr; ++o) 6155 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6156 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6157 /* middle */ 6158 for (i = 0; i < k - 1; ++i) { 6159 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6160 for (n = 0; n < k - 1; ++n) 6161 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6162 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6163 } 6164 /* top */ 6165 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6166 for (o = oetl - 1; o >= oetb; --o) 6167 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6168 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6169 6170 foffset = offset; 6171 } else { 6172 PetscInt dof; 6173 6174 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6175 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6176 foffset = offset; 6177 } 6178 break; 6179 default: 6180 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6181 } 6182 } 6183 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6184 /* Check permutation */ 6185 { 6186 PetscInt *check; 6187 6188 PetscCall(PetscMalloc1(size, &check)); 6189 for (i = 0; i < size; ++i) { 6190 check[i] = -1; 6191 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6192 } 6193 for (i = 0; i < size; ++i) check[perm[i]] = i; 6194 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6195 PetscCall(PetscFree(check)); 6196 } 6197 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6198 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6199 PetscInt *loc_perm; 6200 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6201 for (PetscInt i = 0; i < size; i++) { 6202 loc_perm[i] = perm[i]; 6203 loc_perm[size + i] = size + perm[i]; 6204 } 6205 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6206 } 6207 } 6208 PetscFunctionReturn(PETSC_SUCCESS); 6209 } 6210 6211 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6212 { 6213 PetscDS prob; 6214 PetscInt depth, Nf, h; 6215 DMLabel label; 6216 6217 PetscFunctionBeginHot; 6218 PetscCall(DMGetDS(dm, &prob)); 6219 Nf = prob->Nf; 6220 label = dm->depthLabel; 6221 *dspace = NULL; 6222 if (field < Nf) { 6223 PetscObject disc = prob->disc[field]; 6224 6225 if (disc->classid == PETSCFE_CLASSID) { 6226 PetscDualSpace dsp; 6227 6228 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6229 PetscCall(DMLabelGetNumValues(label, &depth)); 6230 PetscCall(DMLabelGetValue(label, point, &h)); 6231 h = depth - 1 - h; 6232 if (h) { 6233 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6234 } else { 6235 *dspace = dsp; 6236 } 6237 } 6238 } 6239 PetscFunctionReturn(PETSC_SUCCESS); 6240 } 6241 6242 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6243 { 6244 PetscScalar *array; 6245 const PetscScalar *vArray; 6246 const PetscInt *cone, *coneO; 6247 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6248 6249 PetscFunctionBeginHot; 6250 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6251 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6252 PetscCall(DMPlexGetCone(dm, point, &cone)); 6253 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6254 if (!values || !*values) { 6255 if ((point >= pStart) && (point < pEnd)) { 6256 PetscInt dof; 6257 6258 PetscCall(PetscSectionGetDof(section, point, &dof)); 6259 size += dof; 6260 } 6261 for (p = 0; p < numPoints; ++p) { 6262 const PetscInt cp = cone[p]; 6263 PetscInt dof; 6264 6265 if ((cp < pStart) || (cp >= pEnd)) continue; 6266 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6267 size += dof; 6268 } 6269 if (!values) { 6270 if (csize) *csize = size; 6271 PetscFunctionReturn(PETSC_SUCCESS); 6272 } 6273 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6274 } else { 6275 array = *values; 6276 } 6277 size = 0; 6278 PetscCall(VecGetArrayRead(v, &vArray)); 6279 if ((point >= pStart) && (point < pEnd)) { 6280 PetscInt dof, off, d; 6281 const PetscScalar *varr; 6282 6283 PetscCall(PetscSectionGetDof(section, point, &dof)); 6284 PetscCall(PetscSectionGetOffset(section, point, &off)); 6285 varr = PetscSafePointerPlusOffset(vArray, off); 6286 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6287 size += dof; 6288 } 6289 for (p = 0; p < numPoints; ++p) { 6290 const PetscInt cp = cone[p]; 6291 PetscInt o = coneO[p]; 6292 PetscInt dof, off, d; 6293 const PetscScalar *varr; 6294 6295 if ((cp < pStart) || (cp >= pEnd)) continue; 6296 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6297 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6298 varr = PetscSafePointerPlusOffset(vArray, off); 6299 if (o >= 0) { 6300 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6301 } else { 6302 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6303 } 6304 size += dof; 6305 } 6306 PetscCall(VecRestoreArrayRead(v, &vArray)); 6307 if (!*values) { 6308 if (csize) *csize = size; 6309 *values = array; 6310 } else { 6311 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6312 *csize = size; 6313 } 6314 PetscFunctionReturn(PETSC_SUCCESS); 6315 } 6316 6317 /* Compress out points not in the section */ 6318 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6319 { 6320 const PetscInt np = *numPoints; 6321 PetscInt pStart, pEnd, p, q; 6322 6323 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6324 for (p = 0, q = 0; p < np; ++p) { 6325 const PetscInt r = points[p * 2]; 6326 if ((r >= pStart) && (r < pEnd)) { 6327 points[q * 2] = r; 6328 points[q * 2 + 1] = points[p * 2 + 1]; 6329 ++q; 6330 } 6331 } 6332 *numPoints = q; 6333 return PETSC_SUCCESS; 6334 } 6335 6336 /* Compressed closure does not apply closure permutation */ 6337 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6338 { 6339 const PetscInt *cla = NULL; 6340 PetscInt np, *pts = NULL; 6341 6342 PetscFunctionBeginHot; 6343 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6344 if (!ornt && *clPoints) { 6345 PetscInt dof, off; 6346 6347 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6348 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6349 PetscCall(ISGetIndices(*clPoints, &cla)); 6350 np = dof / 2; 6351 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6352 } else { 6353 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6354 PetscCall(CompressPoints_Private(section, &np, pts)); 6355 } 6356 *numPoints = np; 6357 *points = pts; 6358 *clp = cla; 6359 PetscFunctionReturn(PETSC_SUCCESS); 6360 } 6361 6362 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6363 { 6364 PetscFunctionBeginHot; 6365 if (!*clPoints) { 6366 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6367 } else { 6368 PetscCall(ISRestoreIndices(*clPoints, clp)); 6369 } 6370 *numPoints = 0; 6371 *points = NULL; 6372 *clSec = NULL; 6373 *clPoints = NULL; 6374 *clp = NULL; 6375 PetscFunctionReturn(PETSC_SUCCESS); 6376 } 6377 6378 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6379 { 6380 PetscInt offset = 0, p; 6381 const PetscInt **perms = NULL; 6382 const PetscScalar **flips = NULL; 6383 6384 PetscFunctionBeginHot; 6385 *size = 0; 6386 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6387 for (p = 0; p < numPoints; p++) { 6388 const PetscInt point = points[2 * p]; 6389 const PetscInt *perm = perms ? perms[p] : NULL; 6390 const PetscScalar *flip = flips ? flips[p] : NULL; 6391 PetscInt dof, off, d; 6392 const PetscScalar *varr; 6393 6394 PetscCall(PetscSectionGetDof(section, point, &dof)); 6395 PetscCall(PetscSectionGetOffset(section, point, &off)); 6396 varr = PetscSafePointerPlusOffset(vArray, off); 6397 if (clperm) { 6398 if (perm) { 6399 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6400 } else { 6401 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6402 } 6403 if (flip) { 6404 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6405 } 6406 } else { 6407 if (perm) { 6408 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6409 } else { 6410 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6411 } 6412 if (flip) { 6413 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6414 } 6415 } 6416 offset += dof; 6417 } 6418 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6419 *size = offset; 6420 PetscFunctionReturn(PETSC_SUCCESS); 6421 } 6422 6423 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[]) 6424 { 6425 PetscInt offset = 0, f; 6426 6427 PetscFunctionBeginHot; 6428 *size = 0; 6429 for (f = 0; f < numFields; ++f) { 6430 PetscInt p; 6431 const PetscInt **perms = NULL; 6432 const PetscScalar **flips = NULL; 6433 6434 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6435 for (p = 0; p < numPoints; p++) { 6436 const PetscInt point = points[2 * p]; 6437 PetscInt fdof, foff, b; 6438 const PetscScalar *varr; 6439 const PetscInt *perm = perms ? perms[p] : NULL; 6440 const PetscScalar *flip = flips ? flips[p] : NULL; 6441 6442 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6443 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6444 varr = &vArray[foff]; 6445 if (clperm) { 6446 if (perm) { 6447 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6448 } else { 6449 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6450 } 6451 if (flip) { 6452 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6453 } 6454 } else { 6455 if (perm) { 6456 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6457 } else { 6458 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6459 } 6460 if (flip) { 6461 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6462 } 6463 } 6464 offset += fdof; 6465 } 6466 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6467 } 6468 *size = offset; 6469 PetscFunctionReturn(PETSC_SUCCESS); 6470 } 6471 6472 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6473 { 6474 PetscSection clSection; 6475 IS clPoints; 6476 PetscInt *points = NULL; 6477 const PetscInt *clp, *perm = NULL; 6478 PetscInt depth, numFields, numPoints, asize; 6479 6480 PetscFunctionBeginHot; 6481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6482 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6483 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6484 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6485 PetscCall(DMPlexGetDepth(dm, &depth)); 6486 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6487 if (depth == 1 && numFields < 2) { 6488 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6489 PetscFunctionReturn(PETSC_SUCCESS); 6490 } 6491 /* Get points */ 6492 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6493 /* Get sizes */ 6494 asize = 0; 6495 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6496 PetscInt dof; 6497 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6498 asize += dof; 6499 } 6500 if (values) { 6501 const PetscScalar *vArray; 6502 PetscInt size; 6503 6504 if (*values) { 6505 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); 6506 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6507 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6508 PetscCall(VecGetArrayRead(v, &vArray)); 6509 /* Get values */ 6510 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6511 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6512 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6513 /* Cleanup array */ 6514 PetscCall(VecRestoreArrayRead(v, &vArray)); 6515 } 6516 if (csize) *csize = asize; 6517 /* Cleanup points */ 6518 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6519 PetscFunctionReturn(PETSC_SUCCESS); 6520 } 6521 6522 /*@C 6523 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6524 6525 Not collective 6526 6527 Input Parameters: 6528 + dm - The `DM` 6529 . section - The section describing the layout in `v`, or `NULL` to use the default section 6530 . v - The local vector 6531 - point - The point in the `DM` 6532 6533 Input/Output Parameters: 6534 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6535 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6536 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6537 6538 Level: intermediate 6539 6540 Notes: 6541 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6542 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6543 assembly function, and a user may already have allocated storage for this operation. 6544 6545 A typical use could be 6546 .vb 6547 values = NULL; 6548 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6549 for (cl = 0; cl < clSize; ++cl) { 6550 <Compute on closure> 6551 } 6552 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6553 .ve 6554 or 6555 .vb 6556 PetscMalloc1(clMaxSize, &values); 6557 for (p = pStart; p < pEnd; ++p) { 6558 clSize = clMaxSize; 6559 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6560 for (cl = 0; cl < clSize; ++cl) { 6561 <Compute on closure> 6562 } 6563 } 6564 PetscFree(values); 6565 .ve 6566 6567 Fortran Notes: 6568 The `csize` argument is not present in the Fortran binding. 6569 6570 `values` must be declared with 6571 .vb 6572 PetscScalar,dimension(:),pointer :: values 6573 .ve 6574 and it will be allocated internally by PETSc to hold the values returned 6575 6576 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6577 @*/ 6578 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6579 { 6580 PetscFunctionBeginHot; 6581 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6582 PetscFunctionReturn(PETSC_SUCCESS); 6583 } 6584 6585 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6586 { 6587 DMLabel depthLabel; 6588 PetscSection clSection; 6589 IS clPoints; 6590 PetscScalar *array; 6591 const PetscScalar *vArray; 6592 PetscInt *points = NULL; 6593 const PetscInt *clp, *perm = NULL; 6594 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6595 6596 PetscFunctionBeginHot; 6597 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6598 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6599 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6600 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6601 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6602 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6603 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6604 if (mdepth == 1 && numFields < 2) { 6605 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6606 PetscFunctionReturn(PETSC_SUCCESS); 6607 } 6608 /* Get points */ 6609 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6610 for (clsize = 0, p = 0; p < Np; p++) { 6611 PetscInt dof; 6612 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6613 clsize += dof; 6614 } 6615 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6616 /* Filter points */ 6617 for (p = 0; p < numPoints * 2; p += 2) { 6618 PetscInt dep; 6619 6620 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6621 if (dep != depth) continue; 6622 points[Np * 2 + 0] = points[p]; 6623 points[Np * 2 + 1] = points[p + 1]; 6624 ++Np; 6625 } 6626 /* Get array */ 6627 if (!values || !*values) { 6628 PetscInt asize = 0, dof; 6629 6630 for (p = 0; p < Np * 2; p += 2) { 6631 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6632 asize += dof; 6633 } 6634 if (!values) { 6635 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6636 if (csize) *csize = asize; 6637 PetscFunctionReturn(PETSC_SUCCESS); 6638 } 6639 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6640 } else { 6641 array = *values; 6642 } 6643 PetscCall(VecGetArrayRead(v, &vArray)); 6644 /* Get values */ 6645 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6646 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6647 /* Cleanup points */ 6648 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6649 /* Cleanup array */ 6650 PetscCall(VecRestoreArrayRead(v, &vArray)); 6651 if (!*values) { 6652 if (csize) *csize = size; 6653 *values = array; 6654 } else { 6655 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6656 *csize = size; 6657 } 6658 PetscFunctionReturn(PETSC_SUCCESS); 6659 } 6660 6661 /*@C 6662 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6663 6664 Not collective 6665 6666 Input Parameters: 6667 + dm - The `DM` 6668 . section - The section describing the layout in `v`, or `NULL` to use the default section 6669 . v - The local vector 6670 . point - The point in the `DM` 6671 . csize - The number of values in the closure, or `NULL` 6672 - values - The array of values 6673 6674 Level: intermediate 6675 6676 Note: 6677 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6678 6679 Fortran Note: 6680 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6681 6682 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6683 @*/ 6684 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6685 { 6686 PetscInt size = 0; 6687 6688 PetscFunctionBegin; 6689 /* Should work without recalculating size */ 6690 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6691 *values = NULL; 6692 PetscFunctionReturn(PETSC_SUCCESS); 6693 } 6694 6695 static inline void add(PetscScalar *x, PetscScalar y) 6696 { 6697 *x += y; 6698 } 6699 static inline void insert(PetscScalar *x, PetscScalar y) 6700 { 6701 *x = y; 6702 } 6703 6704 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[]) 6705 { 6706 PetscInt cdof; /* The number of constraints on this point */ 6707 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6708 PetscScalar *a; 6709 PetscInt off, cind = 0, k; 6710 6711 PetscFunctionBegin; 6712 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6713 PetscCall(PetscSectionGetOffset(section, point, &off)); 6714 a = &array[off]; 6715 if (!cdof || setBC) { 6716 if (clperm) { 6717 if (perm) { 6718 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6719 } else { 6720 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6721 } 6722 } else { 6723 if (perm) { 6724 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6725 } else { 6726 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6727 } 6728 } 6729 } else { 6730 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6731 if (clperm) { 6732 if (perm) { 6733 for (k = 0; k < dof; ++k) { 6734 if ((cind < cdof) && (k == cdofs[cind])) { 6735 ++cind; 6736 continue; 6737 } 6738 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6739 } 6740 } else { 6741 for (k = 0; k < dof; ++k) { 6742 if ((cind < cdof) && (k == cdofs[cind])) { 6743 ++cind; 6744 continue; 6745 } 6746 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6747 } 6748 } 6749 } else { 6750 if (perm) { 6751 for (k = 0; k < dof; ++k) { 6752 if ((cind < cdof) && (k == cdofs[cind])) { 6753 ++cind; 6754 continue; 6755 } 6756 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6757 } 6758 } else { 6759 for (k = 0; k < dof; ++k) { 6760 if ((cind < cdof) && (k == cdofs[cind])) { 6761 ++cind; 6762 continue; 6763 } 6764 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6765 } 6766 } 6767 } 6768 } 6769 PetscFunctionReturn(PETSC_SUCCESS); 6770 } 6771 6772 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[]) 6773 { 6774 PetscInt cdof; /* The number of constraints on this point */ 6775 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6776 PetscScalar *a; 6777 PetscInt off, cind = 0, k; 6778 6779 PetscFunctionBegin; 6780 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6781 PetscCall(PetscSectionGetOffset(section, point, &off)); 6782 a = &array[off]; 6783 if (cdof) { 6784 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6785 if (clperm) { 6786 if (perm) { 6787 for (k = 0; k < dof; ++k) { 6788 if ((cind < cdof) && (k == cdofs[cind])) { 6789 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6790 cind++; 6791 } 6792 } 6793 } else { 6794 for (k = 0; k < dof; ++k) { 6795 if ((cind < cdof) && (k == cdofs[cind])) { 6796 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6797 cind++; 6798 } 6799 } 6800 } 6801 } else { 6802 if (perm) { 6803 for (k = 0; k < dof; ++k) { 6804 if ((cind < cdof) && (k == cdofs[cind])) { 6805 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6806 cind++; 6807 } 6808 } 6809 } else { 6810 for (k = 0; k < dof; ++k) { 6811 if ((cind < cdof) && (k == cdofs[cind])) { 6812 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6813 cind++; 6814 } 6815 } 6816 } 6817 } 6818 } 6819 PetscFunctionReturn(PETSC_SUCCESS); 6820 } 6821 6822 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[]) 6823 { 6824 PetscScalar *a; 6825 PetscInt fdof, foff, fcdof, foffset = *offset; 6826 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6827 PetscInt cind = 0, b; 6828 6829 PetscFunctionBegin; 6830 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6831 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6832 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6833 a = &array[foff]; 6834 if (!fcdof || setBC) { 6835 if (clperm) { 6836 if (perm) { 6837 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6838 } else { 6839 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6840 } 6841 } else { 6842 if (perm) { 6843 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6844 } else { 6845 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6846 } 6847 } 6848 } else { 6849 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6850 if (clperm) { 6851 if (perm) { 6852 for (b = 0; b < fdof; b++) { 6853 if ((cind < fcdof) && (b == fcdofs[cind])) { 6854 ++cind; 6855 continue; 6856 } 6857 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6858 } 6859 } else { 6860 for (b = 0; b < fdof; b++) { 6861 if ((cind < fcdof) && (b == fcdofs[cind])) { 6862 ++cind; 6863 continue; 6864 } 6865 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6866 } 6867 } 6868 } else { 6869 if (perm) { 6870 for (b = 0; b < fdof; b++) { 6871 if ((cind < fcdof) && (b == fcdofs[cind])) { 6872 ++cind; 6873 continue; 6874 } 6875 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6876 } 6877 } else { 6878 for (b = 0; b < fdof; b++) { 6879 if ((cind < fcdof) && (b == fcdofs[cind])) { 6880 ++cind; 6881 continue; 6882 } 6883 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6884 } 6885 } 6886 } 6887 } 6888 *offset += fdof; 6889 PetscFunctionReturn(PETSC_SUCCESS); 6890 } 6891 6892 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[]) 6893 { 6894 PetscScalar *a; 6895 PetscInt fdof, foff, fcdof, foffset = *offset; 6896 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6897 PetscInt Nc, cind = 0, ncind = 0, b; 6898 PetscBool ncSet, fcSet; 6899 6900 PetscFunctionBegin; 6901 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6902 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6903 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6904 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6905 a = &array[foff]; 6906 if (fcdof) { 6907 /* We just override fcdof and fcdofs with Ncc and comps */ 6908 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6909 if (clperm) { 6910 if (perm) { 6911 if (comps) { 6912 for (b = 0; b < fdof; b++) { 6913 ncSet = fcSet = PETSC_FALSE; 6914 if (b % Nc == comps[ncind]) { 6915 ncind = (ncind + 1) % Ncc; 6916 ncSet = PETSC_TRUE; 6917 } 6918 if ((cind < fcdof) && (b == fcdofs[cind])) { 6919 ++cind; 6920 fcSet = PETSC_TRUE; 6921 } 6922 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6923 } 6924 } else { 6925 for (b = 0; b < fdof; b++) { 6926 if ((cind < fcdof) && (b == fcdofs[cind])) { 6927 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6928 ++cind; 6929 } 6930 } 6931 } 6932 } else { 6933 if (comps) { 6934 for (b = 0; b < fdof; b++) { 6935 ncSet = fcSet = PETSC_FALSE; 6936 if (b % Nc == comps[ncind]) { 6937 ncind = (ncind + 1) % Ncc; 6938 ncSet = PETSC_TRUE; 6939 } 6940 if ((cind < fcdof) && (b == fcdofs[cind])) { 6941 ++cind; 6942 fcSet = PETSC_TRUE; 6943 } 6944 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6945 } 6946 } else { 6947 for (b = 0; b < fdof; b++) { 6948 if ((cind < fcdof) && (b == fcdofs[cind])) { 6949 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6950 ++cind; 6951 } 6952 } 6953 } 6954 } 6955 } else { 6956 if (perm) { 6957 if (comps) { 6958 for (b = 0; b < fdof; b++) { 6959 ncSet = fcSet = PETSC_FALSE; 6960 if (b % Nc == comps[ncind]) { 6961 ncind = (ncind + 1) % Ncc; 6962 ncSet = PETSC_TRUE; 6963 } 6964 if ((cind < fcdof) && (b == fcdofs[cind])) { 6965 ++cind; 6966 fcSet = PETSC_TRUE; 6967 } 6968 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6969 } 6970 } else { 6971 for (b = 0; b < fdof; b++) { 6972 if ((cind < fcdof) && (b == fcdofs[cind])) { 6973 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6974 ++cind; 6975 } 6976 } 6977 } 6978 } else { 6979 if (comps) { 6980 for (b = 0; b < fdof; b++) { 6981 ncSet = fcSet = PETSC_FALSE; 6982 if (b % Nc == comps[ncind]) { 6983 ncind = (ncind + 1) % Ncc; 6984 ncSet = PETSC_TRUE; 6985 } 6986 if ((cind < fcdof) && (b == fcdofs[cind])) { 6987 ++cind; 6988 fcSet = PETSC_TRUE; 6989 } 6990 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6991 } 6992 } else { 6993 for (b = 0; b < fdof; b++) { 6994 if ((cind < fcdof) && (b == fcdofs[cind])) { 6995 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6996 ++cind; 6997 } 6998 } 6999 } 7000 } 7001 } 7002 } 7003 *offset += fdof; 7004 PetscFunctionReturn(PETSC_SUCCESS); 7005 } 7006 7007 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7008 { 7009 PetscScalar *array; 7010 const PetscInt *cone, *coneO; 7011 PetscInt pStart, pEnd, p, numPoints, off, dof; 7012 7013 PetscFunctionBeginHot; 7014 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7015 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7016 PetscCall(DMPlexGetCone(dm, point, &cone)); 7017 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7018 PetscCall(VecGetArray(v, &array)); 7019 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7020 const PetscInt cp = !p ? point : cone[p - 1]; 7021 const PetscInt o = !p ? 0 : coneO[p - 1]; 7022 7023 if ((cp < pStart) || (cp >= pEnd)) { 7024 dof = 0; 7025 continue; 7026 } 7027 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7028 /* ADD_VALUES */ 7029 { 7030 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7031 PetscScalar *a; 7032 PetscInt cdof, coff, cind = 0, k; 7033 7034 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7035 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7036 a = &array[coff]; 7037 if (!cdof) { 7038 if (o >= 0) { 7039 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7040 } else { 7041 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7042 } 7043 } else { 7044 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7045 if (o >= 0) { 7046 for (k = 0; k < dof; ++k) { 7047 if ((cind < cdof) && (k == cdofs[cind])) { 7048 ++cind; 7049 continue; 7050 } 7051 a[k] += values[off + k]; 7052 } 7053 } else { 7054 for (k = 0; k < dof; ++k) { 7055 if ((cind < cdof) && (k == cdofs[cind])) { 7056 ++cind; 7057 continue; 7058 } 7059 a[k] += values[off + dof - k - 1]; 7060 } 7061 } 7062 } 7063 } 7064 } 7065 PetscCall(VecRestoreArray(v, &array)); 7066 PetscFunctionReturn(PETSC_SUCCESS); 7067 } 7068 7069 /*@C 7070 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7071 7072 Not collective 7073 7074 Input Parameters: 7075 + dm - The `DM` 7076 . section - The section describing the layout in `v`, or `NULL` to use the default section 7077 . v - The local vector 7078 . point - The point in the `DM` 7079 . values - The array of values 7080 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7081 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7082 7083 Level: intermediate 7084 7085 Note: 7086 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7087 7088 Fortran Note: 7089 `values` must be declared with 7090 .vb 7091 PetscScalar,dimension(:),pointer :: values 7092 .ve 7093 7094 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7095 @*/ 7096 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7097 { 7098 PetscSection clSection; 7099 IS clPoints; 7100 PetscScalar *array; 7101 PetscInt *points = NULL; 7102 const PetscInt *clp, *clperm = NULL; 7103 PetscInt depth, numFields, numPoints, p, clsize; 7104 7105 PetscFunctionBeginHot; 7106 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7107 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7108 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7109 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7110 PetscCall(DMPlexGetDepth(dm, &depth)); 7111 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7112 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7113 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7114 PetscFunctionReturn(PETSC_SUCCESS); 7115 } 7116 /* Get points */ 7117 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7118 for (clsize = 0, p = 0; p < numPoints; p++) { 7119 PetscInt dof; 7120 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7121 clsize += dof; 7122 } 7123 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7124 /* Get array */ 7125 PetscCall(VecGetArray(v, &array)); 7126 /* Get values */ 7127 if (numFields > 0) { 7128 PetscInt offset = 0, f; 7129 for (f = 0; f < numFields; ++f) { 7130 const PetscInt **perms = NULL; 7131 const PetscScalar **flips = NULL; 7132 7133 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7134 switch (mode) { 7135 case INSERT_VALUES: 7136 for (p = 0; p < numPoints; p++) { 7137 const PetscInt point = points[2 * p]; 7138 const PetscInt *perm = perms ? perms[p] : NULL; 7139 const PetscScalar *flip = flips ? flips[p] : NULL; 7140 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7141 } 7142 break; 7143 case INSERT_ALL_VALUES: 7144 for (p = 0; p < numPoints; p++) { 7145 const PetscInt point = points[2 * p]; 7146 const PetscInt *perm = perms ? perms[p] : NULL; 7147 const PetscScalar *flip = flips ? flips[p] : NULL; 7148 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7149 } 7150 break; 7151 case INSERT_BC_VALUES: 7152 for (p = 0; p < numPoints; p++) { 7153 const PetscInt point = points[2 * p]; 7154 const PetscInt *perm = perms ? perms[p] : NULL; 7155 const PetscScalar *flip = flips ? flips[p] : NULL; 7156 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7157 } 7158 break; 7159 case ADD_VALUES: 7160 for (p = 0; p < numPoints; p++) { 7161 const PetscInt point = points[2 * p]; 7162 const PetscInt *perm = perms ? perms[p] : NULL; 7163 const PetscScalar *flip = flips ? flips[p] : NULL; 7164 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7165 } 7166 break; 7167 case ADD_ALL_VALUES: 7168 for (p = 0; p < numPoints; p++) { 7169 const PetscInt point = points[2 * p]; 7170 const PetscInt *perm = perms ? perms[p] : NULL; 7171 const PetscScalar *flip = flips ? flips[p] : NULL; 7172 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7173 } 7174 break; 7175 case ADD_BC_VALUES: 7176 for (p = 0; p < numPoints; p++) { 7177 const PetscInt point = points[2 * p]; 7178 const PetscInt *perm = perms ? perms[p] : NULL; 7179 const PetscScalar *flip = flips ? flips[p] : NULL; 7180 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7181 } 7182 break; 7183 default: 7184 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7185 } 7186 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7187 } 7188 } else { 7189 PetscInt dof, off; 7190 const PetscInt **perms = NULL; 7191 const PetscScalar **flips = NULL; 7192 7193 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7194 switch (mode) { 7195 case INSERT_VALUES: 7196 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7197 const PetscInt point = points[2 * p]; 7198 const PetscInt *perm = perms ? perms[p] : NULL; 7199 const PetscScalar *flip = flips ? flips[p] : NULL; 7200 PetscCall(PetscSectionGetDof(section, point, &dof)); 7201 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7202 } 7203 break; 7204 case INSERT_ALL_VALUES: 7205 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7206 const PetscInt point = points[2 * p]; 7207 const PetscInt *perm = perms ? perms[p] : NULL; 7208 const PetscScalar *flip = flips ? flips[p] : NULL; 7209 PetscCall(PetscSectionGetDof(section, point, &dof)); 7210 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7211 } 7212 break; 7213 case INSERT_BC_VALUES: 7214 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7215 const PetscInt point = points[2 * p]; 7216 const PetscInt *perm = perms ? perms[p] : NULL; 7217 const PetscScalar *flip = flips ? flips[p] : NULL; 7218 PetscCall(PetscSectionGetDof(section, point, &dof)); 7219 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7220 } 7221 break; 7222 case ADD_VALUES: 7223 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7224 const PetscInt point = points[2 * p]; 7225 const PetscInt *perm = perms ? perms[p] : NULL; 7226 const PetscScalar *flip = flips ? flips[p] : NULL; 7227 PetscCall(PetscSectionGetDof(section, point, &dof)); 7228 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7229 } 7230 break; 7231 case ADD_ALL_VALUES: 7232 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7233 const PetscInt point = points[2 * p]; 7234 const PetscInt *perm = perms ? perms[p] : NULL; 7235 const PetscScalar *flip = flips ? flips[p] : NULL; 7236 PetscCall(PetscSectionGetDof(section, point, &dof)); 7237 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7238 } 7239 break; 7240 case ADD_BC_VALUES: 7241 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7242 const PetscInt point = points[2 * p]; 7243 const PetscInt *perm = perms ? perms[p] : NULL; 7244 const PetscScalar *flip = flips ? flips[p] : NULL; 7245 PetscCall(PetscSectionGetDof(section, point, &dof)); 7246 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7247 } 7248 break; 7249 default: 7250 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7251 } 7252 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7253 } 7254 /* Cleanup points */ 7255 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7256 /* Cleanup array */ 7257 PetscCall(VecRestoreArray(v, &array)); 7258 PetscFunctionReturn(PETSC_SUCCESS); 7259 } 7260 7261 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7262 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7263 { 7264 PetscFunctionBegin; 7265 *contains = PETSC_TRUE; 7266 if (label) { 7267 PetscInt fdof; 7268 7269 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7270 if (!*contains) { 7271 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7272 *offset += fdof; 7273 PetscFunctionReturn(PETSC_SUCCESS); 7274 } 7275 } 7276 PetscFunctionReturn(PETSC_SUCCESS); 7277 } 7278 7279 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7280 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) 7281 { 7282 PetscSection clSection; 7283 IS clPoints; 7284 PetscScalar *array; 7285 PetscInt *points = NULL; 7286 const PetscInt *clp; 7287 PetscInt numFields, numPoints, p; 7288 PetscInt offset = 0, f; 7289 7290 PetscFunctionBeginHot; 7291 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7292 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7293 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7294 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7295 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7296 /* Get points */ 7297 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7298 /* Get array */ 7299 PetscCall(VecGetArray(v, &array)); 7300 /* Get values */ 7301 for (f = 0; f < numFields; ++f) { 7302 const PetscInt **perms = NULL; 7303 const PetscScalar **flips = NULL; 7304 PetscBool contains; 7305 7306 if (!fieldActive[f]) { 7307 for (p = 0; p < numPoints * 2; p += 2) { 7308 PetscInt fdof; 7309 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7310 offset += fdof; 7311 } 7312 continue; 7313 } 7314 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7315 switch (mode) { 7316 case INSERT_VALUES: 7317 for (p = 0; p < numPoints; p++) { 7318 const PetscInt point = points[2 * p]; 7319 const PetscInt *perm = perms ? perms[p] : NULL; 7320 const PetscScalar *flip = flips ? flips[p] : NULL; 7321 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7322 if (!contains) continue; 7323 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7324 } 7325 break; 7326 case INSERT_ALL_VALUES: 7327 for (p = 0; p < numPoints; p++) { 7328 const PetscInt point = points[2 * p]; 7329 const PetscInt *perm = perms ? perms[p] : NULL; 7330 const PetscScalar *flip = flips ? flips[p] : NULL; 7331 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7332 if (!contains) continue; 7333 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7334 } 7335 break; 7336 case INSERT_BC_VALUES: 7337 for (p = 0; p < numPoints; p++) { 7338 const PetscInt point = points[2 * p]; 7339 const PetscInt *perm = perms ? perms[p] : NULL; 7340 const PetscScalar *flip = flips ? flips[p] : NULL; 7341 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7342 if (!contains) continue; 7343 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7344 } 7345 break; 7346 case ADD_VALUES: 7347 for (p = 0; p < numPoints; p++) { 7348 const PetscInt point = points[2 * p]; 7349 const PetscInt *perm = perms ? perms[p] : NULL; 7350 const PetscScalar *flip = flips ? flips[p] : NULL; 7351 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7352 if (!contains) continue; 7353 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7354 } 7355 break; 7356 case ADD_ALL_VALUES: 7357 for (p = 0; p < numPoints; p++) { 7358 const PetscInt point = points[2 * p]; 7359 const PetscInt *perm = perms ? perms[p] : NULL; 7360 const PetscScalar *flip = flips ? flips[p] : NULL; 7361 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7362 if (!contains) continue; 7363 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7364 } 7365 break; 7366 default: 7367 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7368 } 7369 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7370 } 7371 /* Cleanup points */ 7372 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7373 /* Cleanup array */ 7374 PetscCall(VecRestoreArray(v, &array)); 7375 PetscFunctionReturn(PETSC_SUCCESS); 7376 } 7377 7378 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7379 { 7380 PetscMPIInt rank; 7381 PetscInt i, j; 7382 7383 PetscFunctionBegin; 7384 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7385 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7386 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7387 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7388 numCIndices = numCIndices ? numCIndices : numRIndices; 7389 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7390 for (i = 0; i < numRIndices; i++) { 7391 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7392 for (j = 0; j < numCIndices; j++) { 7393 #if defined(PETSC_USE_COMPLEX) 7394 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7395 #else 7396 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7397 #endif 7398 } 7399 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7400 } 7401 PetscFunctionReturn(PETSC_SUCCESS); 7402 } 7403 7404 /* 7405 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7406 7407 Input Parameters: 7408 + section - The section for this data layout 7409 . islocal - Is the section (and thus indices being requested) local or global? 7410 . point - The point contributing dofs with these indices 7411 . off - The global offset of this point 7412 . loff - The local offset of each field 7413 . setBC - The flag determining whether to include indices of boundary values 7414 . perm - A permutation of the dofs on this point, or NULL 7415 - indperm - A permutation of the entire indices array, or NULL 7416 7417 Output Parameter: 7418 . indices - Indices for dofs on this point 7419 7420 Level: developer 7421 7422 Note: The indices could be local or global, depending on the value of 'off'. 7423 */ 7424 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7425 { 7426 PetscInt dof; /* The number of unknowns on this point */ 7427 PetscInt cdof; /* The number of constraints on this point */ 7428 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7429 PetscInt cind = 0, k; 7430 7431 PetscFunctionBegin; 7432 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7433 PetscCall(PetscSectionGetDof(section, point, &dof)); 7434 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7435 if (!cdof || setBC) { 7436 for (k = 0; k < dof; ++k) { 7437 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7438 const PetscInt ind = indperm ? indperm[preind] : preind; 7439 7440 indices[ind] = off + k; 7441 } 7442 } else { 7443 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7444 for (k = 0; k < dof; ++k) { 7445 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7446 const PetscInt ind = indperm ? indperm[preind] : preind; 7447 7448 if ((cind < cdof) && (k == cdofs[cind])) { 7449 /* Insert check for returning constrained indices */ 7450 indices[ind] = -(off + k + 1); 7451 ++cind; 7452 } else { 7453 indices[ind] = off + k - (islocal ? 0 : cind); 7454 } 7455 } 7456 } 7457 *loff += dof; 7458 PetscFunctionReturn(PETSC_SUCCESS); 7459 } 7460 7461 /* 7462 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7463 7464 Input Parameters: 7465 + section - a section (global or local) 7466 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7467 . point - point within section 7468 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7469 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7470 . setBC - identify constrained (boundary condition) points via involution. 7471 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7472 . permsoff - offset 7473 - indperm - index permutation 7474 7475 Output Parameter: 7476 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7477 . indices - array to hold indices (as defined by section) of each dof associated with point 7478 7479 Notes: 7480 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7481 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7482 in the local vector. 7483 7484 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7485 significant). It is invalid to call with a global section and setBC=true. 7486 7487 Developer Note: 7488 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7489 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7490 offset could be obtained from the section instead of passing it explicitly as we do now. 7491 7492 Example: 7493 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7494 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7495 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7496 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. 7497 7498 Level: developer 7499 */ 7500 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[]) 7501 { 7502 PetscInt numFields, foff, f; 7503 7504 PetscFunctionBegin; 7505 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7506 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7507 for (f = 0, foff = 0; f < numFields; ++f) { 7508 PetscInt fdof, cfdof; 7509 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7510 PetscInt cind = 0, b; 7511 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7512 7513 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7514 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7515 if (!cfdof || setBC) { 7516 for (b = 0; b < fdof; ++b) { 7517 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7518 const PetscInt ind = indperm ? indperm[preind] : preind; 7519 7520 indices[ind] = off + foff + b; 7521 } 7522 } else { 7523 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7524 for (b = 0; b < fdof; ++b) { 7525 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7526 const PetscInt ind = indperm ? indperm[preind] : preind; 7527 7528 if ((cind < cfdof) && (b == fcdofs[cind])) { 7529 indices[ind] = -(off + foff + b + 1); 7530 ++cind; 7531 } else { 7532 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7533 } 7534 } 7535 } 7536 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7537 foffs[f] += fdof; 7538 } 7539 PetscFunctionReturn(PETSC_SUCCESS); 7540 } 7541 7542 /* 7543 This version believes the globalSection offsets for each field, rather than just the point offset 7544 7545 . foffs - The offset into 'indices' for each field, since it is segregated by field 7546 7547 Notes: 7548 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7549 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7550 */ 7551 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7552 { 7553 PetscInt numFields, foff, f; 7554 7555 PetscFunctionBegin; 7556 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7557 for (f = 0; f < numFields; ++f) { 7558 PetscInt fdof, cfdof; 7559 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7560 PetscInt cind = 0, b; 7561 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7562 7563 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7564 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7565 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7566 if (!cfdof) { 7567 for (b = 0; b < fdof; ++b) { 7568 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7569 const PetscInt ind = indperm ? indperm[preind] : preind; 7570 7571 indices[ind] = foff + b; 7572 } 7573 } else { 7574 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7575 for (b = 0; b < fdof; ++b) { 7576 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7577 const PetscInt ind = indperm ? indperm[preind] : preind; 7578 7579 if ((cind < cfdof) && (b == fcdofs[cind])) { 7580 indices[ind] = -(foff + b + 1); 7581 ++cind; 7582 } else { 7583 indices[ind] = foff + b - cind; 7584 } 7585 } 7586 } 7587 foffs[f] += fdof; 7588 } 7589 PetscFunctionReturn(PETSC_SUCCESS); 7590 } 7591 7592 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7593 { 7594 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7595 7596 PetscFunctionBegin; 7597 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7598 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7599 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7600 for (PetscInt p = 0; p < nPoints; p++) { 7601 PetscInt b = pnts[2 * p]; 7602 PetscInt bSecDof = 0, bOff; 7603 PetscInt cSecDof = 0; 7604 PetscSection indices_section; 7605 7606 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7607 if (!bSecDof) continue; 7608 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7609 indices_section = cSecDof > 0 ? cSec : section; 7610 if (numFields) { 7611 PetscInt fStart[32], fEnd[32]; 7612 7613 fStart[0] = 0; 7614 fEnd[0] = 0; 7615 for (PetscInt f = 0; f < numFields; f++) { 7616 PetscInt fDof = 0; 7617 7618 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7619 fStart[f + 1] = fStart[f] + fDof; 7620 fEnd[f + 1] = fStart[f + 1]; 7621 } 7622 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7623 // only apply permutations on one side 7624 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7625 for (PetscInt f = 0; f < numFields; f++) { 7626 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7627 } 7628 } else { 7629 PetscInt bEnd = 0; 7630 7631 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7632 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7633 7634 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7635 } 7636 } 7637 PetscFunctionReturn(PETSC_SUCCESS); 7638 } 7639 7640 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[]) 7641 { 7642 Mat cMat; 7643 PetscSection aSec, cSec; 7644 IS aIS; 7645 PetscInt aStart = -1, aEnd = -1; 7646 PetscInt sStart = -1, sEnd = -1; 7647 PetscInt cStart = -1, cEnd = -1; 7648 const PetscInt *anchors; 7649 PetscInt numFields, p; 7650 PetscInt newNumPoints = 0, newNumIndices = 0; 7651 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7652 PetscInt oldOffsets[32]; 7653 PetscInt newOffsets[32]; 7654 PetscInt oldOffsetsCopy[32]; 7655 PetscInt newOffsetsCopy[32]; 7656 PetscScalar *modMat = NULL; 7657 PetscBool anyConstrained = PETSC_FALSE; 7658 7659 PetscFunctionBegin; 7660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7661 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7662 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7663 7664 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7665 /* if there are point-to-point constraints */ 7666 if (aSec) { 7667 PetscCall(PetscArrayzero(newOffsets, 32)); 7668 PetscCall(PetscArrayzero(oldOffsets, 32)); 7669 PetscCall(ISGetIndices(aIS, &anchors)); 7670 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7671 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7672 /* figure out how many points are going to be in the new element matrix 7673 * (we allow double counting, because it's all just going to be summed 7674 * into the global matrix anyway) */ 7675 for (p = 0; p < 2 * numPoints; p += 2) { 7676 PetscInt b = points[p]; 7677 PetscInt bDof = 0, bSecDof = 0; 7678 7679 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7680 if (!bSecDof) continue; 7681 7682 for (PetscInt f = 0; f < numFields; f++) { 7683 PetscInt fDof = 0; 7684 7685 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7686 oldOffsets[f + 1] += fDof; 7687 } 7688 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7689 if (bDof) { 7690 /* this point is constrained */ 7691 /* it is going to be replaced by its anchors */ 7692 PetscInt bOff, q; 7693 7694 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7695 for (q = 0; q < bDof; q++) { 7696 PetscInt a = anchors[bOff + q]; 7697 PetscInt aDof = 0; 7698 7699 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7700 if (aDof) { 7701 anyConstrained = PETSC_TRUE; 7702 newNumPoints += 1; 7703 } 7704 newNumIndices += aDof; 7705 for (PetscInt f = 0; f < numFields; ++f) { 7706 PetscInt fDof = 0; 7707 7708 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7709 newOffsets[f + 1] += fDof; 7710 } 7711 } 7712 } else { 7713 /* this point is not constrained */ 7714 newNumPoints++; 7715 newNumIndices += bSecDof; 7716 for (PetscInt f = 0; f < numFields; ++f) { 7717 PetscInt fDof; 7718 7719 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7720 newOffsets[f + 1] += fDof; 7721 } 7722 } 7723 } 7724 } 7725 if (!anyConstrained) { 7726 if (outNumPoints) *outNumPoints = 0; 7727 if (outNumIndices) *outNumIndices = 0; 7728 if (outPoints) *outPoints = NULL; 7729 if (outMat) *outMat = NULL; 7730 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7731 PetscFunctionReturn(PETSC_SUCCESS); 7732 } 7733 7734 if (outNumPoints) *outNumPoints = newNumPoints; 7735 if (outNumIndices) *outNumIndices = newNumIndices; 7736 7737 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7738 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7739 7740 if (!outPoints && !outMat) { 7741 if (offsets) { 7742 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7743 } 7744 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7745 PetscFunctionReturn(PETSC_SUCCESS); 7746 } 7747 7748 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7749 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7750 7751 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7752 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7753 7754 /* output arrays */ 7755 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7756 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7757 7758 // get the new Points 7759 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7760 PetscInt b = points[2 * p]; 7761 PetscInt bDof = 0, bSecDof = 0, bOff; 7762 7763 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7764 if (!bSecDof) continue; 7765 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7766 if (bDof) { 7767 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7768 for (PetscInt q = 0; q < bDof; q++) { 7769 PetscInt a = anchors[bOff + q], aDof = 0; 7770 7771 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7772 if (aDof) { 7773 newPoints[2 * newP] = a; 7774 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7775 newP++; 7776 } 7777 } 7778 } else { 7779 newPoints[2 * newP] = b; 7780 newPoints[2 * newP + 1] = points[2 * p + 1]; 7781 newP++; 7782 } 7783 } 7784 7785 if (outMat) { 7786 PetscScalar *tmpMat; 7787 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7788 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7789 7790 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7791 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7792 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7793 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7794 7795 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7796 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7797 7798 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7799 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7800 7801 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7802 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7803 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7804 // for each field, insert the anchor modification into modMat 7805 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7806 PetscInt fStart = oldOffsets[f]; 7807 PetscInt fNewStart = newOffsets[f]; 7808 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7809 PetscInt b = points[2 * p]; 7810 PetscInt bDof = 0, bSecDof = 0, bOff; 7811 7812 if (b >= sStart && b < sEnd) { 7813 if (numFields) { 7814 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7815 } else { 7816 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7817 } 7818 } 7819 if (!bSecDof) continue; 7820 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7821 if (bDof) { 7822 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7823 for (PetscInt q = 0; q < bDof; q++, newP++) { 7824 PetscInt a = anchors[bOff + q], aDof = 0; 7825 7826 if (a >= sStart && a < sEnd) { 7827 if (numFields) { 7828 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7829 } else { 7830 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7831 } 7832 } 7833 if (aDof) { 7834 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7835 for (PetscInt d = 0; d < bSecDof; d++) { 7836 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7837 } 7838 } 7839 oNew += aDof; 7840 } 7841 } else { 7842 // Insert the identity matrix in this block 7843 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7844 oNew += bSecDof; 7845 newP++; 7846 } 7847 o += bSecDof; 7848 } 7849 } 7850 7851 *outMat = modMat; 7852 7853 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7854 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7855 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7856 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7857 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7858 } 7859 PetscCall(ISRestoreIndices(aIS, &anchors)); 7860 7861 /* output */ 7862 if (outPoints) { 7863 *outPoints = newPoints; 7864 } else { 7865 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7866 } 7867 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7868 PetscFunctionReturn(PETSC_SUCCESS); 7869 } 7870 7871 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) 7872 { 7873 PetscScalar *modMat = NULL; 7874 PetscInt newNumIndices = -1; 7875 7876 PetscFunctionBegin; 7877 /* 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. 7878 modMat is that matrix C */ 7879 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7880 if (outNumIndices) *outNumIndices = newNumIndices; 7881 if (modMat) { 7882 const PetscScalar *newValues = values; 7883 7884 if (multiplyRight) { 7885 PetscScalar *newNewValues = NULL; 7886 PetscBLASInt M = newNumIndices; 7887 PetscBLASInt N = numRows; 7888 PetscBLASInt K = numIndices; 7889 PetscScalar a = 1.0, b = 0.0; 7890 7891 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); 7892 7893 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7894 // row-major to column-major conversion, right multiplication becomes left multiplication 7895 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7896 7897 numCols = newNumIndices; 7898 newValues = newNewValues; 7899 } 7900 7901 if (multiplyLeft) { 7902 PetscScalar *newNewValues = NULL; 7903 PetscBLASInt M = numCols; 7904 PetscBLASInt N = newNumIndices; 7905 PetscBLASInt K = numIndices; 7906 PetscScalar a = 1.0, b = 0.0; 7907 7908 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); 7909 7910 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7911 // row-major to column-major conversion, left multiplication becomes right multiplication 7912 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7913 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7914 newValues = newNewValues; 7915 } 7916 *outValues = (PetscScalar *)newValues; 7917 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7918 } 7919 PetscFunctionReturn(PETSC_SUCCESS); 7920 } 7921 7922 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) 7923 { 7924 PetscFunctionBegin; 7925 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7926 PetscFunctionReturn(PETSC_SUCCESS); 7927 } 7928 7929 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7930 { 7931 /* Closure ordering */ 7932 PetscSection clSection; 7933 IS clPoints; 7934 const PetscInt *clp; 7935 PetscInt *points; 7936 PetscInt Ncl, Ni = 0; 7937 7938 PetscFunctionBeginHot; 7939 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7940 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7941 PetscInt dof; 7942 7943 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7944 Ni += dof; 7945 } 7946 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7947 *closureSize = Ni; 7948 PetscFunctionReturn(PETSC_SUCCESS); 7949 } 7950 7951 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) 7952 { 7953 /* Closure ordering */ 7954 PetscSection clSection; 7955 IS clPoints; 7956 const PetscInt *clp; 7957 PetscInt *points; 7958 const PetscInt *clperm = NULL; 7959 /* Dof permutation and sign flips */ 7960 const PetscInt **perms[32] = {NULL}; 7961 const PetscScalar **flips[32] = {NULL}; 7962 PetscScalar *valCopy = NULL; 7963 /* Hanging node constraints */ 7964 PetscInt *pointsC = NULL; 7965 PetscScalar *valuesC = NULL; 7966 PetscInt NclC, NiC; 7967 7968 PetscInt *idx; 7969 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7970 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7971 PetscInt idxStart, idxEnd; 7972 PetscInt nRows, nCols; 7973 7974 PetscFunctionBeginHot; 7975 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7976 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7977 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7978 PetscAssertPointer(numRows, 6); 7979 PetscAssertPointer(numCols, 7); 7980 if (indices) PetscAssertPointer(indices, 8); 7981 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7982 if (values) PetscAssertPointer(values, 10); 7983 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7984 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7985 PetscCall(PetscArrayzero(offsets, 32)); 7986 /* 1) Get points in closure */ 7987 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7988 if (useClPerm) { 7989 PetscInt depth, clsize; 7990 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7991 for (clsize = 0, p = 0; p < Ncl; p++) { 7992 PetscInt dof; 7993 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7994 clsize += dof; 7995 } 7996 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7997 } 7998 /* 2) Get number of indices on these points and field offsets from section */ 7999 for (p = 0; p < Ncl * 2; p += 2) { 8000 PetscInt dof, fdof; 8001 8002 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8003 for (f = 0; f < Nf; ++f) { 8004 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8005 offsets[f + 1] += fdof; 8006 } 8007 Ni += dof; 8008 } 8009 if (*numRows == -1) *numRows = Ni; 8010 if (*numCols == -1) *numCols = Ni; 8011 nRows = *numRows; 8012 nCols = *numCols; 8013 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8014 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8015 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8016 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8017 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8018 for (f = 0; f < PetscMax(1, Nf); ++f) { 8019 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8020 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8021 /* may need to apply sign changes to the element matrix */ 8022 if (values && flips[f]) { 8023 PetscInt foffset = offsets[f]; 8024 8025 for (p = 0; p < Ncl; ++p) { 8026 PetscInt pnt = points[2 * p], fdof; 8027 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8028 8029 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8030 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8031 if (flip) { 8032 PetscInt i, j, k; 8033 8034 if (!valCopy) { 8035 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8036 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8037 *values = valCopy; 8038 } 8039 for (i = 0; i < fdof; ++i) { 8040 PetscScalar fval = flip[i]; 8041 8042 if (multiplyRight) { 8043 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8044 } 8045 if (multiplyLeft) { 8046 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8047 } 8048 } 8049 } 8050 foffset += fdof; 8051 } 8052 } 8053 } 8054 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8055 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8056 if (NclC) { 8057 if (multiplyRight) { *numCols = nCols = NiC; } 8058 if (multiplyLeft) { *numRows = nRows = NiC; } 8059 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8060 for (f = 0; f < PetscMax(1, Nf); ++f) { 8061 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8062 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8063 } 8064 for (f = 0; f < PetscMax(1, Nf); ++f) { 8065 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8066 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8067 } 8068 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8069 Ncl = NclC; 8070 Ni = NiC; 8071 points = pointsC; 8072 if (values) *values = valuesC; 8073 } 8074 /* 5) Calculate indices */ 8075 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8076 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8077 if (Nf) { 8078 PetscInt idxOff; 8079 PetscBool useFieldOffsets; 8080 8081 if (outOffsets) { 8082 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8083 } 8084 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8085 if (useFieldOffsets) { 8086 for (p = 0; p < Ncl; ++p) { 8087 const PetscInt pnt = points[p * 2]; 8088 8089 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8090 } 8091 } else { 8092 for (p = 0; p < Ncl; ++p) { 8093 const PetscInt pnt = points[p * 2]; 8094 8095 if (pnt < idxStart || pnt >= idxEnd) continue; 8096 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8097 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8098 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8099 * global section. */ 8100 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8101 } 8102 } 8103 } else { 8104 PetscInt off = 0, idxOff; 8105 8106 for (p = 0; p < Ncl; ++p) { 8107 const PetscInt pnt = points[p * 2]; 8108 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8109 8110 if (pnt < idxStart || pnt >= idxEnd) continue; 8111 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8112 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8113 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8114 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8115 } 8116 } 8117 /* 6) Cleanup */ 8118 for (f = 0; f < PetscMax(1, Nf); ++f) { 8119 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8120 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8121 } 8122 if (NclC) { 8123 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8124 } else { 8125 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8126 } 8127 8128 if (indices) *indices = idx; 8129 PetscFunctionReturn(PETSC_SUCCESS); 8130 } 8131 8132 /*@C 8133 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8134 8135 Not collective 8136 8137 Input Parameters: 8138 + dm - The `DM` 8139 . section - The `PetscSection` describing the points (a local section) 8140 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8141 . point - The point defining the closure 8142 - useClPerm - Use the closure point permutation if available 8143 8144 Output Parameters: 8145 + numIndices - The number of dof indices in the closure of point with the input sections 8146 . indices - The dof indices 8147 . outOffsets - Array to write the field offsets into, or `NULL` 8148 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8149 8150 Level: advanced 8151 8152 Notes: 8153 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8154 8155 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8156 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8157 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8158 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8159 indices (with the above semantics) are implied. 8160 8161 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8162 `PetscSection`, `DMGetGlobalSection()` 8163 @*/ 8164 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8165 { 8166 PetscInt numRows = -1, numCols = -1; 8167 8168 PetscFunctionBeginHot; 8169 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8170 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8171 *numIndices = numRows; 8172 PetscFunctionReturn(PETSC_SUCCESS); 8173 } 8174 8175 /*@C 8176 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8177 8178 Not collective 8179 8180 Input Parameters: 8181 + dm - The `DM` 8182 . section - The `PetscSection` describing the points (a local section) 8183 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8184 . point - The point defining the closure 8185 - useClPerm - Use the closure point permutation if available 8186 8187 Output Parameters: 8188 + numIndices - The number of dof indices in the closure of point with the input sections 8189 . indices - The dof indices 8190 . outOffsets - Array to write the field offsets into, or `NULL` 8191 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8192 8193 Level: advanced 8194 8195 Notes: 8196 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8197 8198 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8199 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8200 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8201 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8202 indices (with the above semantics) are implied. 8203 8204 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8205 @*/ 8206 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8207 { 8208 PetscFunctionBegin; 8209 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8210 PetscAssertPointer(indices, 7); 8211 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8212 PetscFunctionReturn(PETSC_SUCCESS); 8213 } 8214 8215 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8216 { 8217 DM_Plex *mesh = (DM_Plex *)dm->data; 8218 PetscInt *indices; 8219 PetscInt numIndices; 8220 const PetscScalar *valuesOrig = values; 8221 PetscErrorCode ierr; 8222 8223 PetscFunctionBegin; 8224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8225 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8226 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8227 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8228 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8229 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8230 8231 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8232 8233 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8234 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8235 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8236 if (ierr) { 8237 PetscMPIInt rank; 8238 8239 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8240 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8241 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8242 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8243 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8244 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8245 } 8246 if (mesh->printFEM > 1) { 8247 PetscInt i; 8248 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8249 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8250 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8251 } 8252 8253 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8254 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8255 PetscFunctionReturn(PETSC_SUCCESS); 8256 } 8257 8258 /*@C 8259 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8260 8261 Not collective 8262 8263 Input Parameters: 8264 + dm - The `DM` 8265 . section - The section describing the layout in `v`, or `NULL` to use the default section 8266 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8267 . A - The matrix 8268 . point - The point in the `DM` 8269 . values - The array of values 8270 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8271 8272 Level: intermediate 8273 8274 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8275 @*/ 8276 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8277 { 8278 PetscFunctionBegin; 8279 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8280 PetscFunctionReturn(PETSC_SUCCESS); 8281 } 8282 8283 /*@C 8284 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8285 8286 Not collective 8287 8288 Input Parameters: 8289 + dmRow - The `DM` for the row fields 8290 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8291 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8292 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8293 . dmCol - The `DM` for the column fields 8294 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8295 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8296 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8297 . A - The matrix 8298 . point - The point in the `DM` 8299 . values - The array of values 8300 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8301 8302 Level: intermediate 8303 8304 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8305 @*/ 8306 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) 8307 { 8308 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8309 PetscInt *indicesRow, *indicesCol; 8310 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8311 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8312 8313 PetscErrorCode ierr; 8314 8315 PetscFunctionBegin; 8316 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8317 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8318 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8319 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8320 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8321 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8322 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8323 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8324 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8325 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8326 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8327 8328 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8329 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8330 valuesV1 = valuesV0; 8331 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8332 valuesV2 = valuesV1; 8333 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8334 8335 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8336 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8337 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8338 if (ierr) { 8339 PetscMPIInt rank; 8340 8341 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8342 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8343 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8344 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8345 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8346 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8347 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8348 } 8349 8350 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8351 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8352 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8353 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8354 PetscFunctionReturn(PETSC_SUCCESS); 8355 } 8356 8357 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8358 { 8359 DM_Plex *mesh = (DM_Plex *)dmf->data; 8360 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8361 PetscInt *cpoints = NULL; 8362 PetscInt *findices, *cindices; 8363 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8364 PetscInt foffsets[32], coffsets[32]; 8365 DMPolytopeType ct; 8366 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8367 PetscErrorCode ierr; 8368 8369 PetscFunctionBegin; 8370 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8371 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8372 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8373 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8374 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8375 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8376 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8377 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8378 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8379 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8380 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8381 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8382 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8383 PetscCall(PetscArrayzero(foffsets, 32)); 8384 PetscCall(PetscArrayzero(coffsets, 32)); 8385 /* Column indices */ 8386 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8387 maxFPoints = numCPoints; 8388 /* Compress out points not in the section */ 8389 /* TODO: Squeeze out points with 0 dof as well */ 8390 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8391 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8392 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8393 cpoints[q * 2] = cpoints[p]; 8394 cpoints[q * 2 + 1] = cpoints[p + 1]; 8395 ++q; 8396 } 8397 } 8398 numCPoints = q; 8399 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8400 PetscInt fdof; 8401 8402 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8403 if (!dof) continue; 8404 for (f = 0; f < numFields; ++f) { 8405 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8406 coffsets[f + 1] += fdof; 8407 } 8408 numCIndices += dof; 8409 } 8410 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8411 /* Row indices */ 8412 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8413 { 8414 DMPlexTransform tr; 8415 DMPolytopeType *rct; 8416 PetscInt *rsize, *rcone, *rornt, Nt; 8417 8418 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8419 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8420 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8421 numSubcells = rsize[Nt - 1]; 8422 PetscCall(DMPlexTransformDestroy(&tr)); 8423 } 8424 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8425 for (r = 0, q = 0; r < numSubcells; ++r) { 8426 /* TODO Map from coarse to fine cells */ 8427 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8428 /* Compress out points not in the section */ 8429 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8430 for (p = 0; p < numFPoints * 2; p += 2) { 8431 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8432 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8433 if (!dof) continue; 8434 for (s = 0; s < q; ++s) 8435 if (fpoints[p] == ftotpoints[s * 2]) break; 8436 if (s < q) continue; 8437 ftotpoints[q * 2] = fpoints[p]; 8438 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8439 ++q; 8440 } 8441 } 8442 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8443 } 8444 numFPoints = q; 8445 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8446 PetscInt fdof; 8447 8448 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8449 if (!dof) continue; 8450 for (f = 0; f < numFields; ++f) { 8451 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8452 foffsets[f + 1] += fdof; 8453 } 8454 numFIndices += dof; 8455 } 8456 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8457 8458 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8459 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8460 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8461 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8462 if (numFields) { 8463 const PetscInt **permsF[32] = {NULL}; 8464 const PetscInt **permsC[32] = {NULL}; 8465 8466 for (f = 0; f < numFields; f++) { 8467 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8468 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8469 } 8470 for (p = 0; p < numFPoints; p++) { 8471 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8472 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8473 } 8474 for (p = 0; p < numCPoints; p++) { 8475 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8476 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8477 } 8478 for (f = 0; f < numFields; f++) { 8479 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8480 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8481 } 8482 } else { 8483 const PetscInt **permsF = NULL; 8484 const PetscInt **permsC = NULL; 8485 8486 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8487 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8488 for (p = 0, off = 0; p < numFPoints; p++) { 8489 const PetscInt *perm = permsF ? permsF[p] : NULL; 8490 8491 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8492 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8493 } 8494 for (p = 0, off = 0; p < numCPoints; p++) { 8495 const PetscInt *perm = permsC ? permsC[p] : NULL; 8496 8497 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8498 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8499 } 8500 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8501 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8502 } 8503 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8504 /* TODO: flips */ 8505 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8506 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8507 if (ierr) { 8508 PetscMPIInt rank; 8509 8510 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8511 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8512 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8513 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8514 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8515 } 8516 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8517 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8518 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8519 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8520 PetscFunctionReturn(PETSC_SUCCESS); 8521 } 8522 8523 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8524 { 8525 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8526 PetscInt *cpoints = NULL; 8527 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8528 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8529 DMPolytopeType ct; 8530 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8531 8532 PetscFunctionBegin; 8533 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8534 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8535 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8536 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8537 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8538 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8539 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8540 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8541 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8542 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8543 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8544 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8545 /* Column indices */ 8546 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8547 maxFPoints = numCPoints; 8548 /* Compress out points not in the section */ 8549 /* TODO: Squeeze out points with 0 dof as well */ 8550 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8551 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8552 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8553 cpoints[q * 2] = cpoints[p]; 8554 cpoints[q * 2 + 1] = cpoints[p + 1]; 8555 ++q; 8556 } 8557 } 8558 numCPoints = q; 8559 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8560 PetscInt fdof; 8561 8562 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8563 if (!dof) continue; 8564 for (f = 0; f < numFields; ++f) { 8565 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8566 coffsets[f + 1] += fdof; 8567 } 8568 numCIndices += dof; 8569 } 8570 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8571 /* Row indices */ 8572 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8573 { 8574 DMPlexTransform tr; 8575 DMPolytopeType *rct; 8576 PetscInt *rsize, *rcone, *rornt, Nt; 8577 8578 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8579 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8580 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8581 numSubcells = rsize[Nt - 1]; 8582 PetscCall(DMPlexTransformDestroy(&tr)); 8583 } 8584 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8585 for (r = 0, q = 0; r < numSubcells; ++r) { 8586 /* TODO Map from coarse to fine cells */ 8587 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8588 /* Compress out points not in the section */ 8589 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8590 for (p = 0; p < numFPoints * 2; p += 2) { 8591 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8592 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8593 if (!dof) continue; 8594 for (s = 0; s < q; ++s) 8595 if (fpoints[p] == ftotpoints[s * 2]) break; 8596 if (s < q) continue; 8597 ftotpoints[q * 2] = fpoints[p]; 8598 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8599 ++q; 8600 } 8601 } 8602 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8603 } 8604 numFPoints = q; 8605 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8606 PetscInt fdof; 8607 8608 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8609 if (!dof) continue; 8610 for (f = 0; f < numFields; ++f) { 8611 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8612 foffsets[f + 1] += fdof; 8613 } 8614 numFIndices += dof; 8615 } 8616 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8617 8618 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8619 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8620 if (numFields) { 8621 const PetscInt **permsF[32] = {NULL}; 8622 const PetscInt **permsC[32] = {NULL}; 8623 8624 for (f = 0; f < numFields; f++) { 8625 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8626 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8627 } 8628 for (p = 0; p < numFPoints; p++) { 8629 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8630 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8631 } 8632 for (p = 0; p < numCPoints; p++) { 8633 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8634 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8635 } 8636 for (f = 0; f < numFields; f++) { 8637 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8638 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8639 } 8640 } else { 8641 const PetscInt **permsF = NULL; 8642 const PetscInt **permsC = NULL; 8643 8644 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8645 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8646 for (p = 0, off = 0; p < numFPoints; p++) { 8647 const PetscInt *perm = permsF ? permsF[p] : NULL; 8648 8649 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8650 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8651 } 8652 for (p = 0, off = 0; p < numCPoints; p++) { 8653 const PetscInt *perm = permsC ? permsC[p] : NULL; 8654 8655 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8656 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8657 } 8658 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8659 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8660 } 8661 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8662 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8663 PetscFunctionReturn(PETSC_SUCCESS); 8664 } 8665 8666 /*@ 8667 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8668 8669 Input Parameter: 8670 . dm - The `DMPLEX` object 8671 8672 Output Parameter: 8673 . cellHeight - The height of a cell 8674 8675 Level: developer 8676 8677 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8678 @*/ 8679 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8680 { 8681 DM_Plex *mesh = (DM_Plex *)dm->data; 8682 8683 PetscFunctionBegin; 8684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8685 PetscAssertPointer(cellHeight, 2); 8686 *cellHeight = mesh->vtkCellHeight; 8687 PetscFunctionReturn(PETSC_SUCCESS); 8688 } 8689 8690 /*@ 8691 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8692 8693 Input Parameters: 8694 + dm - The `DMPLEX` object 8695 - cellHeight - The height of a cell 8696 8697 Level: developer 8698 8699 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8700 @*/ 8701 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8702 { 8703 DM_Plex *mesh = (DM_Plex *)dm->data; 8704 8705 PetscFunctionBegin; 8706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8707 mesh->vtkCellHeight = cellHeight; 8708 PetscFunctionReturn(PETSC_SUCCESS); 8709 } 8710 8711 /*@ 8712 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8713 8714 Input Parameters: 8715 + dm - The `DMPLEX` object 8716 - ct - The `DMPolytopeType` of the cell 8717 8718 Output Parameters: 8719 + start - The first cell of this type, or `NULL` 8720 - end - The upper bound on this celltype, or `NULL` 8721 8722 Level: advanced 8723 8724 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8725 @*/ 8726 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8727 { 8728 DM_Plex *mesh = (DM_Plex *)dm->data; 8729 DMLabel label; 8730 PetscInt pStart, pEnd; 8731 8732 PetscFunctionBegin; 8733 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8734 if (start) { 8735 PetscAssertPointer(start, 3); 8736 *start = 0; 8737 } 8738 if (end) { 8739 PetscAssertPointer(end, 4); 8740 *end = 0; 8741 } 8742 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8743 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8744 if (mesh->tr) { 8745 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8746 } else { 8747 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8748 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8749 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8750 } 8751 PetscFunctionReturn(PETSC_SUCCESS); 8752 } 8753 8754 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8755 { 8756 PetscSection section, globalSection; 8757 PetscInt *numbers, p; 8758 8759 PetscFunctionBegin; 8760 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8761 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8762 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8763 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8764 PetscCall(PetscSectionSetUp(section)); 8765 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8766 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8767 for (p = pStart; p < pEnd; ++p) { 8768 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8769 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8770 else numbers[p - pStart] += shift; 8771 } 8772 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8773 if (globalSize) { 8774 PetscLayout layout; 8775 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8776 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8777 PetscCall(PetscLayoutDestroy(&layout)); 8778 } 8779 PetscCall(PetscSectionDestroy(§ion)); 8780 PetscCall(PetscSectionDestroy(&globalSection)); 8781 PetscFunctionReturn(PETSC_SUCCESS); 8782 } 8783 8784 /*@ 8785 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8786 8787 Input Parameters: 8788 + dm - The `DMPLEX` object 8789 - includeAll - Whether to include all cells, or just the simplex and box cells 8790 8791 Output Parameter: 8792 . globalCellNumbers - Global cell numbers for all cells on this process 8793 8794 Level: developer 8795 8796 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8797 @*/ 8798 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8799 { 8800 PetscInt cellHeight, cStart, cEnd; 8801 8802 PetscFunctionBegin; 8803 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8804 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8805 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8806 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8807 PetscFunctionReturn(PETSC_SUCCESS); 8808 } 8809 8810 /*@ 8811 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8812 8813 Input Parameter: 8814 . dm - The `DMPLEX` object 8815 8816 Output Parameter: 8817 . globalCellNumbers - Global cell numbers for all cells on this process 8818 8819 Level: developer 8820 8821 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8822 @*/ 8823 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8824 { 8825 DM_Plex *mesh = (DM_Plex *)dm->data; 8826 8827 PetscFunctionBegin; 8828 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8829 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8830 *globalCellNumbers = mesh->globalCellNumbers; 8831 PetscFunctionReturn(PETSC_SUCCESS); 8832 } 8833 8834 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8835 { 8836 PetscInt vStart, vEnd; 8837 8838 PetscFunctionBegin; 8839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8840 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8841 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8842 PetscFunctionReturn(PETSC_SUCCESS); 8843 } 8844 8845 /*@ 8846 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8847 8848 Input Parameter: 8849 . dm - The `DMPLEX` object 8850 8851 Output Parameter: 8852 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8853 8854 Level: developer 8855 8856 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8857 @*/ 8858 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8859 { 8860 DM_Plex *mesh = (DM_Plex *)dm->data; 8861 8862 PetscFunctionBegin; 8863 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8864 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8865 *globalVertexNumbers = mesh->globalVertexNumbers; 8866 PetscFunctionReturn(PETSC_SUCCESS); 8867 } 8868 8869 /*@ 8870 DMPlexCreatePointNumbering - Create a global numbering for all points. 8871 8872 Collective 8873 8874 Input Parameter: 8875 . dm - The `DMPLEX` object 8876 8877 Output Parameter: 8878 . globalPointNumbers - Global numbers for all points on this process 8879 8880 Level: developer 8881 8882 Notes: 8883 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8884 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8885 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8886 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8887 8888 The partitioned mesh is 8889 ``` 8890 (2)--0--(3)--1--(4) (1)--0--(2) 8891 ``` 8892 and its global numbering is 8893 ``` 8894 (3)--0--(4)--1--(5)--2--(6) 8895 ``` 8896 Then the global numbering is provided as 8897 ``` 8898 [0] Number of indices in set 5 8899 [0] 0 0 8900 [0] 1 1 8901 [0] 2 3 8902 [0] 3 4 8903 [0] 4 -6 8904 [1] Number of indices in set 3 8905 [1] 0 2 8906 [1] 1 5 8907 [1] 2 6 8908 ``` 8909 8910 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8911 @*/ 8912 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8913 { 8914 IS nums[4]; 8915 PetscInt depths[4], gdepths[4], starts[4]; 8916 PetscInt depth, d, shift = 0; 8917 PetscBool empty = PETSC_FALSE; 8918 8919 PetscFunctionBegin; 8920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8921 PetscCall(DMPlexGetDepth(dm, &depth)); 8922 // For unstratified meshes use dim instead of depth 8923 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8924 // If any stratum is empty, we must mark all empty 8925 for (d = 0; d <= depth; ++d) { 8926 PetscInt end; 8927 8928 depths[d] = depth - d; 8929 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8930 if (!(starts[d] - end)) empty = PETSC_TRUE; 8931 } 8932 if (empty) 8933 for (d = 0; d <= depth; ++d) { 8934 depths[d] = -1; 8935 starts[d] = -1; 8936 } 8937 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8938 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8939 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]); 8940 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8941 for (d = 0; d <= depth; ++d) { 8942 PetscInt pStart, pEnd, gsize; 8943 8944 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8945 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8946 shift += gsize; 8947 } 8948 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8949 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8950 PetscFunctionReturn(PETSC_SUCCESS); 8951 } 8952 8953 /*@ 8954 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8955 8956 Collective 8957 8958 Input Parameter: 8959 . dm - The `DMPLEX` object 8960 8961 Output Parameter: 8962 . globalEdgeNumbers - Global numbers for all edges on this process 8963 8964 Level: developer 8965 8966 Notes: 8967 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). 8968 8969 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8970 @*/ 8971 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8972 { 8973 PetscSF sf; 8974 PetscInt eStart, eEnd; 8975 8976 PetscFunctionBegin; 8977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8978 PetscCall(DMGetPointSF(dm, &sf)); 8979 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8980 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8981 PetscFunctionReturn(PETSC_SUCCESS); 8982 } 8983 8984 /*@ 8985 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8986 8987 Input Parameter: 8988 . dm - The `DMPLEX` object 8989 8990 Output Parameter: 8991 . ranks - The rank field 8992 8993 Options Database Key: 8994 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8995 8996 Level: intermediate 8997 8998 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8999 @*/ 9000 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9001 { 9002 DM rdm; 9003 PetscFE fe; 9004 PetscScalar *r; 9005 PetscMPIInt rank; 9006 DMPolytopeType ct; 9007 PetscInt dim, cStart, cEnd, c; 9008 PetscBool simplex; 9009 9010 PetscFunctionBeginUser; 9011 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9012 PetscAssertPointer(ranks, 2); 9013 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9014 PetscCall(DMClone(dm, &rdm)); 9015 PetscCall(DMGetDimension(rdm, &dim)); 9016 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9017 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9018 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9019 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9020 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9021 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9022 PetscCall(PetscFEDestroy(&fe)); 9023 PetscCall(DMCreateDS(rdm)); 9024 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9025 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9026 PetscCall(VecGetArray(*ranks, &r)); 9027 for (c = cStart; c < cEnd; ++c) { 9028 PetscScalar *lr; 9029 9030 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9031 if (lr) *lr = rank; 9032 } 9033 PetscCall(VecRestoreArray(*ranks, &r)); 9034 PetscCall(DMDestroy(&rdm)); 9035 PetscFunctionReturn(PETSC_SUCCESS); 9036 } 9037 9038 /*@ 9039 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9040 9041 Input Parameters: 9042 + dm - The `DMPLEX` 9043 - label - The `DMLabel` 9044 9045 Output Parameter: 9046 . val - The label value field 9047 9048 Options Database Key: 9049 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9050 9051 Level: intermediate 9052 9053 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9054 @*/ 9055 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9056 { 9057 DM rdm, plex; 9058 Vec lval; 9059 PetscSection section; 9060 PetscFE fe; 9061 PetscScalar *v; 9062 PetscInt dim, pStart, pEnd, p, cStart; 9063 DMPolytopeType ct; 9064 char name[PETSC_MAX_PATH_LEN]; 9065 const char *lname, *prefix; 9066 9067 PetscFunctionBeginUser; 9068 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9069 PetscAssertPointer(label, 2); 9070 PetscAssertPointer(val, 3); 9071 PetscCall(DMClone(dm, &rdm)); 9072 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9073 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9074 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9075 PetscCall(DMDestroy(&plex)); 9076 PetscCall(DMGetDimension(rdm, &dim)); 9077 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9078 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9079 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9080 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9081 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9082 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9083 PetscCall(PetscFEDestroy(&fe)); 9084 PetscCall(DMCreateDS(rdm)); 9085 PetscCall(DMCreateGlobalVector(rdm, val)); 9086 PetscCall(DMCreateLocalVector(rdm, &lval)); 9087 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9088 PetscCall(DMGetLocalSection(rdm, §ion)); 9089 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9090 PetscCall(VecGetArray(lval, &v)); 9091 for (p = pStart; p < pEnd; ++p) { 9092 PetscInt cval, dof, off; 9093 9094 PetscCall(PetscSectionGetDof(section, p, &dof)); 9095 if (!dof) continue; 9096 PetscCall(DMLabelGetValue(label, p, &cval)); 9097 PetscCall(PetscSectionGetOffset(section, p, &off)); 9098 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9099 } 9100 PetscCall(VecRestoreArray(lval, &v)); 9101 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9102 PetscCall(VecDestroy(&lval)); 9103 PetscCall(DMDestroy(&rdm)); 9104 PetscFunctionReturn(PETSC_SUCCESS); 9105 } 9106 9107 /*@ 9108 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9109 9110 Input Parameter: 9111 . dm - The `DMPLEX` object 9112 9113 Level: developer 9114 9115 Notes: 9116 This is a useful diagnostic when creating meshes programmatically. 9117 9118 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9119 9120 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9121 @*/ 9122 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9123 { 9124 PetscSection coneSection, supportSection; 9125 const PetscInt *cone, *support; 9126 PetscInt coneSize, c, supportSize, s; 9127 PetscInt pStart, pEnd, p, pp, csize, ssize; 9128 PetscBool storagecheck = PETSC_TRUE; 9129 9130 PetscFunctionBegin; 9131 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9132 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9133 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9134 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9135 /* Check that point p is found in the support of its cone points, and vice versa */ 9136 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9137 for (p = pStart; p < pEnd; ++p) { 9138 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9139 PetscCall(DMPlexGetCone(dm, p, &cone)); 9140 for (c = 0; c < coneSize; ++c) { 9141 PetscBool dup = PETSC_FALSE; 9142 PetscInt d; 9143 for (d = c - 1; d >= 0; --d) { 9144 if (cone[c] == cone[d]) { 9145 dup = PETSC_TRUE; 9146 break; 9147 } 9148 } 9149 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9150 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9151 for (s = 0; s < supportSize; ++s) { 9152 if (support[s] == p) break; 9153 } 9154 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9155 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9156 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9157 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9158 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9159 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9160 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9161 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]); 9162 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9163 } 9164 } 9165 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9166 if (p != pp) { 9167 storagecheck = PETSC_FALSE; 9168 continue; 9169 } 9170 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9171 PetscCall(DMPlexGetSupport(dm, p, &support)); 9172 for (s = 0; s < supportSize; ++s) { 9173 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9174 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9175 for (c = 0; c < coneSize; ++c) { 9176 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9177 if (cone[c] != pp) { 9178 c = 0; 9179 break; 9180 } 9181 if (cone[c] == p) break; 9182 } 9183 if (c >= coneSize) { 9184 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9185 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9186 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9187 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9188 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9189 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9190 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9191 } 9192 } 9193 } 9194 if (storagecheck) { 9195 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9196 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9197 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9198 } 9199 PetscFunctionReturn(PETSC_SUCCESS); 9200 } 9201 9202 /* 9203 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. 9204 */ 9205 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9206 { 9207 DMPolytopeType cct; 9208 PetscInt ptpoints[4]; 9209 const PetscInt *cone, *ccone, *ptcone; 9210 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9211 9212 PetscFunctionBegin; 9213 *unsplit = 0; 9214 switch (ct) { 9215 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9216 ptpoints[npt++] = c; 9217 break; 9218 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9219 PetscCall(DMPlexGetCone(dm, c, &cone)); 9220 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9221 for (cp = 0; cp < coneSize; ++cp) { 9222 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9223 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9224 } 9225 break; 9226 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9227 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9228 PetscCall(DMPlexGetCone(dm, c, &cone)); 9229 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9230 for (cp = 0; cp < coneSize; ++cp) { 9231 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9232 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9233 for (ccp = 0; ccp < cconeSize; ++ccp) { 9234 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9235 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9236 PetscInt p; 9237 for (p = 0; p < npt; ++p) 9238 if (ptpoints[p] == ccone[ccp]) break; 9239 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9240 } 9241 } 9242 } 9243 break; 9244 default: 9245 break; 9246 } 9247 for (pt = 0; pt < npt; ++pt) { 9248 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9249 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9250 } 9251 PetscFunctionReturn(PETSC_SUCCESS); 9252 } 9253 9254 /*@ 9255 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9256 9257 Input Parameters: 9258 + dm - The `DMPLEX` object 9259 - cellHeight - Normally 0 9260 9261 Level: developer 9262 9263 Notes: 9264 This is a useful diagnostic when creating meshes programmatically. 9265 Currently applicable only to homogeneous simplex or tensor meshes. 9266 9267 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9268 9269 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9270 @*/ 9271 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9272 { 9273 DMPlexInterpolatedFlag interp; 9274 DMPolytopeType ct; 9275 PetscInt vStart, vEnd, cStart, cEnd, c; 9276 9277 PetscFunctionBegin; 9278 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9279 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9280 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9281 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9282 for (c = cStart; c < cEnd; ++c) { 9283 PetscInt *closure = NULL; 9284 PetscInt coneSize, closureSize, cl, Nv = 0; 9285 9286 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9287 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9288 if (interp == DMPLEX_INTERPOLATED_FULL) { 9289 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9290 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)); 9291 } 9292 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9293 for (cl = 0; cl < closureSize * 2; cl += 2) { 9294 const PetscInt p = closure[cl]; 9295 if ((p >= vStart) && (p < vEnd)) ++Nv; 9296 } 9297 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9298 /* Special Case: Tensor faces with identified vertices */ 9299 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9300 PetscInt unsplit; 9301 9302 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9303 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9304 } 9305 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)); 9306 } 9307 PetscFunctionReturn(PETSC_SUCCESS); 9308 } 9309 9310 /*@ 9311 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9312 9313 Collective 9314 9315 Input Parameters: 9316 + dm - The `DMPLEX` object 9317 - cellHeight - Normally 0 9318 9319 Level: developer 9320 9321 Notes: 9322 This is a useful diagnostic when creating meshes programmatically. 9323 This routine is only relevant for meshes that are fully interpolated across all ranks. 9324 It will error out if a partially interpolated mesh is given on some rank. 9325 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9326 9327 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9328 9329 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9330 @*/ 9331 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9332 { 9333 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9334 DMPlexInterpolatedFlag interpEnum; 9335 9336 PetscFunctionBegin; 9337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9338 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9339 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9340 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9341 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9342 PetscFunctionReturn(PETSC_SUCCESS); 9343 } 9344 9345 PetscCall(DMGetDimension(dm, &dim)); 9346 PetscCall(DMPlexGetDepth(dm, &depth)); 9347 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9348 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9349 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9350 for (c = cStart; c < cEnd; ++c) { 9351 const PetscInt *cone, *ornt, *faceSizes, *faces; 9352 const DMPolytopeType *faceTypes; 9353 DMPolytopeType ct; 9354 PetscInt numFaces, coneSize, f; 9355 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9356 9357 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9358 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9359 if (unsplit) continue; 9360 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9361 PetscCall(DMPlexGetCone(dm, c, &cone)); 9362 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9363 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9364 for (cl = 0; cl < closureSize * 2; cl += 2) { 9365 const PetscInt p = closure[cl]; 9366 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9367 } 9368 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9369 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); 9370 for (f = 0; f < numFaces; ++f) { 9371 DMPolytopeType fct; 9372 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9373 9374 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9375 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9376 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9377 const PetscInt p = fclosure[cl]; 9378 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9379 } 9380 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]); 9381 for (v = 0; v < fnumCorners; ++v) { 9382 if (fclosure[v] != faces[fOff + v]) { 9383 PetscInt v1; 9384 9385 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9386 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9387 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9388 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9389 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9390 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]); 9391 } 9392 } 9393 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9394 fOff += faceSizes[f]; 9395 } 9396 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9397 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9398 } 9399 } 9400 PetscFunctionReturn(PETSC_SUCCESS); 9401 } 9402 9403 /*@ 9404 DMPlexCheckGeometry - Check the geometry of mesh cells 9405 9406 Input Parameter: 9407 . dm - The `DMPLEX` object 9408 9409 Level: developer 9410 9411 Notes: 9412 This is a useful diagnostic when creating meshes programmatically. 9413 9414 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9415 9416 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9417 @*/ 9418 PetscErrorCode DMPlexCheckGeometry(DM dm) 9419 { 9420 Vec coordinates; 9421 PetscReal detJ, J[9], refVol = 1.0; 9422 PetscReal vol; 9423 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9424 9425 PetscFunctionBegin; 9426 PetscCall(DMGetDimension(dm, &dim)); 9427 PetscCall(DMGetCoordinateDim(dm, &dE)); 9428 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9429 PetscCall(DMPlexGetDepth(dm, &depth)); 9430 for (d = 0; d < dim; ++d) refVol *= 2.0; 9431 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9432 /* Make sure local coordinates are created, because that step is collective */ 9433 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9434 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9435 for (c = cStart; c < cEnd; ++c) { 9436 DMPolytopeType ct; 9437 PetscInt unsplit; 9438 PetscBool ignoreZeroVol = PETSC_FALSE; 9439 9440 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9441 switch (ct) { 9442 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9443 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9444 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9445 ignoreZeroVol = PETSC_TRUE; 9446 break; 9447 default: 9448 break; 9449 } 9450 switch (ct) { 9451 case DM_POLYTOPE_TRI_PRISM: 9452 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9453 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9454 case DM_POLYTOPE_PYRAMID: 9455 continue; 9456 default: 9457 break; 9458 } 9459 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9460 if (unsplit) continue; 9461 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9462 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); 9463 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9464 /* This should work with periodicity since DG coordinates should be used */ 9465 if (depth > 1) { 9466 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9467 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); 9468 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9469 } 9470 } 9471 PetscFunctionReturn(PETSC_SUCCESS); 9472 } 9473 9474 /*@ 9475 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9476 9477 Collective 9478 9479 Input Parameters: 9480 + dm - The `DMPLEX` object 9481 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9482 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9483 9484 Level: developer 9485 9486 Notes: 9487 This is mainly intended for debugging/testing purposes. 9488 9489 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9490 9491 Extra roots can come from periodic cuts, where additional points appear on the boundary 9492 9493 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9494 @*/ 9495 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9496 { 9497 PetscInt l, nleaves, nroots, overlap; 9498 const PetscInt *locals; 9499 const PetscSFNode *remotes; 9500 PetscBool distributed; 9501 MPI_Comm comm; 9502 PetscMPIInt rank; 9503 9504 PetscFunctionBegin; 9505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9506 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9507 else pointSF = dm->sf; 9508 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9509 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9510 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9511 { 9512 PetscMPIInt mpiFlag; 9513 9514 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9515 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9516 } 9517 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9518 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9519 if (!distributed) { 9520 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); 9521 PetscFunctionReturn(PETSC_SUCCESS); 9522 } 9523 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); 9524 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9525 9526 /* Check SF graph is compatible with DMPlex chart */ 9527 { 9528 PetscInt pStart, pEnd, maxLeaf; 9529 9530 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9531 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9532 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9533 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9534 } 9535 9536 /* Check Point SF has no local points referenced */ 9537 for (l = 0; l < nleaves; l++) { 9538 PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index); 9539 } 9540 9541 /* Check there are no cells in interface */ 9542 if (!overlap) { 9543 PetscInt cellHeight, cStart, cEnd; 9544 9545 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9546 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9547 for (l = 0; l < nleaves; ++l) { 9548 const PetscInt point = locals ? locals[l] : l; 9549 9550 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9551 } 9552 } 9553 9554 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9555 { 9556 const PetscInt *rootdegree; 9557 9558 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9559 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9560 for (l = 0; l < nleaves; ++l) { 9561 const PetscInt point = locals ? locals[l] : l; 9562 const PetscInt *cone; 9563 PetscInt coneSize, c, idx; 9564 9565 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9566 PetscCall(DMPlexGetCone(dm, point, &cone)); 9567 for (c = 0; c < coneSize; ++c) { 9568 if (!rootdegree[cone[c]]) { 9569 if (locals) { 9570 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9571 } else { 9572 idx = (cone[c] < nleaves) ? cone[c] : -1; 9573 } 9574 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9575 } 9576 } 9577 } 9578 } 9579 PetscFunctionReturn(PETSC_SUCCESS); 9580 } 9581 9582 /*@ 9583 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9584 9585 Collective 9586 9587 Input Parameter: 9588 . dm - The `DMPLEX` object 9589 9590 Level: developer 9591 9592 Notes: 9593 This is mainly intended for debugging/testing purposes. 9594 9595 Other cell types which are disconnected would be caught by the symmetry and face checks. 9596 9597 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9598 9599 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9600 @*/ 9601 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9602 { 9603 PetscInt pStart, pEnd, vStart, vEnd; 9604 9605 PetscFunctionBegin; 9606 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9607 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9608 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9609 for (PetscInt v = vStart; v < vEnd; ++v) { 9610 PetscInt suppSize; 9611 9612 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9613 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9614 } 9615 PetscFunctionReturn(PETSC_SUCCESS); 9616 } 9617 9618 /*@ 9619 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9620 9621 Input Parameter: 9622 . dm - The `DMPLEX` object 9623 9624 Level: developer 9625 9626 Notes: 9627 This is a useful diagnostic when creating meshes programmatically. 9628 9629 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9630 9631 Currently does not include `DMPlexCheckCellShape()`. 9632 9633 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9634 @*/ 9635 PetscErrorCode DMPlexCheck(DM dm) 9636 { 9637 PetscInt cellHeight; 9638 9639 PetscFunctionBegin; 9640 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9641 PetscCall(DMPlexCheckSymmetry(dm)); 9642 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9643 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9644 PetscCall(DMPlexCheckGeometry(dm)); 9645 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9646 PetscCall(DMPlexCheckInterfaceCones(dm)); 9647 PetscCall(DMPlexCheckOrphanVertices(dm)); 9648 PetscFunctionReturn(PETSC_SUCCESS); 9649 } 9650 9651 typedef struct cell_stats { 9652 PetscReal min, max, sum, squaresum; 9653 PetscInt count; 9654 } cell_stats_t; 9655 9656 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9657 { 9658 PetscInt i, N = *len; 9659 9660 for (i = 0; i < N; i++) { 9661 cell_stats_t *A = (cell_stats_t *)a; 9662 cell_stats_t *B = (cell_stats_t *)b; 9663 9664 B->min = PetscMin(A->min, B->min); 9665 B->max = PetscMax(A->max, B->max); 9666 B->sum += A->sum; 9667 B->squaresum += A->squaresum; 9668 B->count += A->count; 9669 } 9670 } 9671 9672 /*@ 9673 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9674 9675 Collective 9676 9677 Input Parameters: 9678 + dm - The `DMPLEX` object 9679 . output - If true, statistics will be displayed on `stdout` 9680 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9681 9682 Level: developer 9683 9684 Notes: 9685 This is mainly intended for debugging/testing purposes. 9686 9687 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9688 9689 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9690 @*/ 9691 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9692 { 9693 DM dmCoarse; 9694 cell_stats_t stats, globalStats; 9695 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9696 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9697 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9698 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9699 PetscMPIInt rank, size; 9700 9701 PetscFunctionBegin; 9702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9703 stats.min = PETSC_MAX_REAL; 9704 stats.max = PETSC_MIN_REAL; 9705 stats.sum = stats.squaresum = 0.; 9706 stats.count = 0; 9707 9708 PetscCallMPI(MPI_Comm_size(comm, &size)); 9709 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9710 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9711 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9712 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9713 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9714 for (c = cStart; c < cEnd; c++) { 9715 PetscInt i; 9716 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9717 9718 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9719 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9720 for (i = 0; i < PetscSqr(cdim); ++i) { 9721 frobJ += J[i] * J[i]; 9722 frobInvJ += invJ[i] * invJ[i]; 9723 } 9724 cond2 = frobJ * frobInvJ; 9725 cond = PetscSqrtReal(cond2); 9726 9727 stats.min = PetscMin(stats.min, cond); 9728 stats.max = PetscMax(stats.max, cond); 9729 stats.sum += cond; 9730 stats.squaresum += cond2; 9731 stats.count++; 9732 if (output && cond > limit) { 9733 PetscSection coordSection; 9734 Vec coordsLocal; 9735 PetscScalar *coords = NULL; 9736 PetscInt Nv, d, clSize, cl, *closure = NULL; 9737 9738 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9739 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9740 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9741 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9742 for (i = 0; i < Nv / cdim; ++i) { 9743 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9744 for (d = 0; d < cdim; ++d) { 9745 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9746 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9747 } 9748 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9749 } 9750 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9751 for (cl = 0; cl < clSize * 2; cl += 2) { 9752 const PetscInt edge = closure[cl]; 9753 9754 if ((edge >= eStart) && (edge < eEnd)) { 9755 PetscReal len; 9756 9757 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9758 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9759 } 9760 } 9761 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9762 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9763 } 9764 } 9765 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9766 9767 if (size > 1) { 9768 PetscMPIInt blockLengths[2] = {4, 1}; 9769 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9770 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9771 MPI_Op statReduce; 9772 9773 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9774 PetscCallMPI(MPI_Type_commit(&statType)); 9775 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9776 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9777 PetscCallMPI(MPI_Op_free(&statReduce)); 9778 PetscCallMPI(MPI_Type_free(&statType)); 9779 } else { 9780 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9781 } 9782 if (rank == 0) { 9783 count = globalStats.count; 9784 min = globalStats.min; 9785 max = globalStats.max; 9786 mean = globalStats.sum / globalStats.count; 9787 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9788 } 9789 9790 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)); 9791 PetscCall(PetscFree2(J, invJ)); 9792 9793 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9794 if (dmCoarse) { 9795 PetscBool isplex; 9796 9797 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9798 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9799 } 9800 PetscFunctionReturn(PETSC_SUCCESS); 9801 } 9802 9803 /*@ 9804 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9805 orthogonal quality below given tolerance. 9806 9807 Collective 9808 9809 Input Parameters: 9810 + dm - The `DMPLEX` object 9811 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9812 - atol - [0, 1] Absolute tolerance for tagging cells. 9813 9814 Output Parameters: 9815 + OrthQual - `Vec` containing orthogonal quality per cell 9816 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9817 9818 Options Database Keys: 9819 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9820 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9821 9822 Level: intermediate 9823 9824 Notes: 9825 Orthogonal quality is given by the following formula\: 9826 9827 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9828 9829 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 9830 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9831 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9832 calculating the cosine of the angle between these vectors. 9833 9834 Orthogonal quality ranges from 1 (best) to 0 (worst). 9835 9836 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9837 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9838 9839 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9840 9841 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9842 @*/ 9843 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9844 { 9845 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9846 PetscInt *idx; 9847 PetscScalar *oqVals; 9848 const PetscScalar *cellGeomArr, *faceGeomArr; 9849 PetscReal *ci, *fi, *Ai; 9850 MPI_Comm comm; 9851 Vec cellgeom, facegeom; 9852 DM dmFace, dmCell; 9853 IS glob; 9854 ISLocalToGlobalMapping ltog; 9855 PetscViewer vwr; 9856 9857 PetscFunctionBegin; 9858 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9859 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9860 PetscAssertPointer(OrthQual, 4); 9861 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9862 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9863 PetscCall(DMGetDimension(dm, &nc)); 9864 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9865 { 9866 DMPlexInterpolatedFlag interpFlag; 9867 9868 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9869 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9870 PetscMPIInt rank; 9871 9872 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9873 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9874 } 9875 } 9876 if (OrthQualLabel) { 9877 PetscAssertPointer(OrthQualLabel, 5); 9878 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9879 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9880 } else { 9881 *OrthQualLabel = NULL; 9882 } 9883 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9884 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9885 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9886 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9887 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9888 PetscCall(VecCreate(comm, OrthQual)); 9889 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9890 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9891 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9892 PetscCall(VecSetUp(*OrthQual)); 9893 PetscCall(ISDestroy(&glob)); 9894 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9895 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9896 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9897 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9898 PetscCall(VecGetDM(cellgeom, &dmCell)); 9899 PetscCall(VecGetDM(facegeom, &dmFace)); 9900 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9901 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9902 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9903 PetscInt cellarr[2], *adj = NULL; 9904 PetscScalar *cArr, *fArr; 9905 PetscReal minvalc = 1.0, minvalf = 1.0; 9906 PetscFVCellGeom *cg; 9907 9908 idx[cellIter] = cell - cStart; 9909 cellarr[0] = cell; 9910 /* Make indexing into cellGeom easier */ 9911 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9912 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9913 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9914 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9915 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9916 PetscInt i; 9917 const PetscInt neigh = adj[cellneigh]; 9918 PetscReal normci = 0, normfi = 0, normai = 0; 9919 PetscFVCellGeom *cgneigh; 9920 PetscFVFaceGeom *fg; 9921 9922 /* Don't count ourselves in the neighbor list */ 9923 if (neigh == cell) continue; 9924 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9925 cellarr[1] = neigh; 9926 { 9927 PetscInt numcovpts; 9928 const PetscInt *covpts; 9929 9930 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9931 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9932 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9933 } 9934 9935 /* Compute c_i, f_i and their norms */ 9936 for (i = 0; i < nc; i++) { 9937 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9938 fi[i] = fg->centroid[i] - cg->centroid[i]; 9939 Ai[i] = fg->normal[i]; 9940 normci += PetscPowReal(ci[i], 2); 9941 normfi += PetscPowReal(fi[i], 2); 9942 normai += PetscPowReal(Ai[i], 2); 9943 } 9944 normci = PetscSqrtReal(normci); 9945 normfi = PetscSqrtReal(normfi); 9946 normai = PetscSqrtReal(normai); 9947 9948 /* Normalize and compute for each face-cell-normal pair */ 9949 for (i = 0; i < nc; i++) { 9950 ci[i] = ci[i] / normci; 9951 fi[i] = fi[i] / normfi; 9952 Ai[i] = Ai[i] / normai; 9953 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9954 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9955 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9956 } 9957 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9958 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9959 } 9960 PetscCall(PetscFree(adj)); 9961 PetscCall(PetscFree2(cArr, fArr)); 9962 /* Defer to cell if they're equal */ 9963 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9964 if (OrthQualLabel) { 9965 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9966 } 9967 } 9968 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9969 PetscCall(VecAssemblyBegin(*OrthQual)); 9970 PetscCall(VecAssemblyEnd(*OrthQual)); 9971 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9972 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9973 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9974 if (OrthQualLabel) { 9975 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9976 } 9977 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9978 PetscCall(PetscViewerDestroy(&vwr)); 9979 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9980 PetscFunctionReturn(PETSC_SUCCESS); 9981 } 9982 9983 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9984 * interpolator construction */ 9985 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9986 { 9987 PetscSection section, newSection, gsection; 9988 PetscSF sf; 9989 PetscBool hasConstraints, ghasConstraints; 9990 9991 PetscFunctionBegin; 9992 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9993 PetscAssertPointer(odm, 2); 9994 PetscCall(DMGetLocalSection(dm, §ion)); 9995 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9996 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9997 if (!ghasConstraints) { 9998 PetscCall(PetscObjectReference((PetscObject)dm)); 9999 *odm = dm; 10000 PetscFunctionReturn(PETSC_SUCCESS); 10001 } 10002 PetscCall(DMClone(dm, odm)); 10003 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10004 PetscCall(DMGetLocalSection(*odm, &newSection)); 10005 PetscCall(DMGetPointSF(*odm, &sf)); 10006 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10007 PetscCall(DMSetGlobalSection(*odm, gsection)); 10008 PetscCall(PetscSectionDestroy(&gsection)); 10009 PetscFunctionReturn(PETSC_SUCCESS); 10010 } 10011 10012 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10013 { 10014 DM dmco, dmfo; 10015 Mat interpo; 10016 Vec rscale; 10017 Vec cglobalo, clocal; 10018 Vec fglobal, fglobalo, flocal; 10019 PetscBool regular; 10020 10021 PetscFunctionBegin; 10022 PetscCall(DMGetFullDM(dmc, &dmco)); 10023 PetscCall(DMGetFullDM(dmf, &dmfo)); 10024 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10025 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10026 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10027 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10028 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10029 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10030 PetscCall(VecSet(cglobalo, 0.)); 10031 PetscCall(VecSet(clocal, 0.)); 10032 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10033 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10034 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10035 PetscCall(VecSet(fglobal, 0.)); 10036 PetscCall(VecSet(fglobalo, 0.)); 10037 PetscCall(VecSet(flocal, 0.)); 10038 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10039 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10040 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10041 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10042 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10043 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10044 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10045 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10046 *shift = fglobal; 10047 PetscCall(VecDestroy(&flocal)); 10048 PetscCall(VecDestroy(&fglobalo)); 10049 PetscCall(VecDestroy(&clocal)); 10050 PetscCall(VecDestroy(&cglobalo)); 10051 PetscCall(VecDestroy(&rscale)); 10052 PetscCall(MatDestroy(&interpo)); 10053 PetscCall(DMDestroy(&dmfo)); 10054 PetscCall(DMDestroy(&dmco)); 10055 PetscFunctionReturn(PETSC_SUCCESS); 10056 } 10057 10058 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10059 { 10060 PetscObject shifto; 10061 Vec shift; 10062 10063 PetscFunctionBegin; 10064 if (!interp) { 10065 Vec rscale; 10066 10067 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10068 PetscCall(VecDestroy(&rscale)); 10069 } else { 10070 PetscCall(PetscObjectReference((PetscObject)interp)); 10071 } 10072 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10073 if (!shifto) { 10074 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10075 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10076 shifto = (PetscObject)shift; 10077 PetscCall(VecDestroy(&shift)); 10078 } 10079 shift = (Vec)shifto; 10080 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10081 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10082 PetscCall(MatDestroy(&interp)); 10083 PetscFunctionReturn(PETSC_SUCCESS); 10084 } 10085 10086 /* Pointwise interpolation 10087 Just code FEM for now 10088 u^f = I u^c 10089 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10090 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10091 I_{ij} = psi^f_i phi^c_j 10092 */ 10093 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10094 { 10095 PetscSection gsc, gsf; 10096 PetscInt m, n; 10097 void *ctx; 10098 DM cdm; 10099 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10100 10101 PetscFunctionBegin; 10102 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10103 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10104 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10105 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10106 10107 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10108 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10109 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10110 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10111 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10112 10113 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10114 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10115 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10116 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10117 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10118 if (scaling) { 10119 /* Use naive scaling */ 10120 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10121 } 10122 PetscFunctionReturn(PETSC_SUCCESS); 10123 } 10124 10125 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10126 { 10127 VecScatter ctx; 10128 10129 PetscFunctionBegin; 10130 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10131 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10132 PetscCall(VecScatterDestroy(&ctx)); 10133 PetscFunctionReturn(PETSC_SUCCESS); 10134 } 10135 10136 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[]) 10137 { 10138 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10139 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10140 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10141 } 10142 10143 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10144 { 10145 DM dmc; 10146 PetscDS ds; 10147 Vec ones, locmass; 10148 IS cellIS; 10149 PetscFormKey key; 10150 PetscInt depth; 10151 10152 PetscFunctionBegin; 10153 PetscCall(DMClone(dm, &dmc)); 10154 PetscCall(DMCopyDisc(dm, dmc)); 10155 PetscCall(DMGetDS(dmc, &ds)); 10156 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10157 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10158 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10159 else PetscCall(DMGetLocalVector(dm, &locmass)); 10160 PetscCall(DMGetLocalVector(dm, &ones)); 10161 PetscCall(DMPlexGetDepth(dm, &depth)); 10162 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10163 PetscCall(VecSet(locmass, 0.0)); 10164 PetscCall(VecSet(ones, 1.0)); 10165 key.label = NULL; 10166 key.value = 0; 10167 key.field = 0; 10168 key.part = 0; 10169 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10170 PetscCall(ISDestroy(&cellIS)); 10171 if (mass) { 10172 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10173 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10174 } 10175 PetscCall(DMRestoreLocalVector(dm, &ones)); 10176 if (lmass) *lmass = locmass; 10177 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10178 PetscCall(DMDestroy(&dmc)); 10179 PetscFunctionReturn(PETSC_SUCCESS); 10180 } 10181 10182 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10183 { 10184 PetscSection gsc, gsf; 10185 PetscInt m, n; 10186 void *ctx; 10187 DM cdm; 10188 PetscBool regular; 10189 10190 PetscFunctionBegin; 10191 if (dmFine == dmCoarse) { 10192 DM dmc; 10193 PetscDS ds; 10194 PetscWeakForm wf; 10195 Vec u; 10196 IS cellIS; 10197 PetscFormKey key; 10198 PetscInt depth; 10199 10200 PetscCall(DMClone(dmFine, &dmc)); 10201 PetscCall(DMCopyDisc(dmFine, dmc)); 10202 PetscCall(DMGetDS(dmc, &ds)); 10203 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10204 PetscCall(PetscWeakFormClear(wf)); 10205 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10206 PetscCall(DMCreateMatrix(dmc, mass)); 10207 PetscCall(DMGetLocalVector(dmc, &u)); 10208 PetscCall(DMPlexGetDepth(dmc, &depth)); 10209 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10210 PetscCall(MatZeroEntries(*mass)); 10211 key.label = NULL; 10212 key.value = 0; 10213 key.field = 0; 10214 key.part = 0; 10215 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10216 PetscCall(ISDestroy(&cellIS)); 10217 PetscCall(DMRestoreLocalVector(dmc, &u)); 10218 PetscCall(DMDestroy(&dmc)); 10219 } else { 10220 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10221 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10222 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10223 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10224 10225 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10226 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10227 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10228 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10229 10230 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10231 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10232 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10233 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10234 } 10235 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10236 PetscFunctionReturn(PETSC_SUCCESS); 10237 } 10238 10239 /*@ 10240 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10241 10242 Input Parameter: 10243 . dm - The `DMPLEX` object 10244 10245 Output Parameter: 10246 . regular - The flag 10247 10248 Level: intermediate 10249 10250 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10251 @*/ 10252 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10253 { 10254 PetscFunctionBegin; 10255 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10256 PetscAssertPointer(regular, 2); 10257 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10258 PetscFunctionReturn(PETSC_SUCCESS); 10259 } 10260 10261 /*@ 10262 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10263 10264 Input Parameters: 10265 + dm - The `DMPLEX` object 10266 - regular - The flag 10267 10268 Level: intermediate 10269 10270 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10271 @*/ 10272 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10273 { 10274 PetscFunctionBegin; 10275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10276 ((DM_Plex *)dm->data)->regularRefinement = regular; 10277 PetscFunctionReturn(PETSC_SUCCESS); 10278 } 10279 10280 /*@ 10281 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10282 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10283 10284 Not Collective 10285 10286 Input Parameter: 10287 . dm - The `DMPLEX` object 10288 10289 Output Parameters: 10290 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10291 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10292 10293 Level: intermediate 10294 10295 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10296 @*/ 10297 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10298 { 10299 DM_Plex *plex = (DM_Plex *)dm->data; 10300 10301 PetscFunctionBegin; 10302 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10303 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10304 if (anchorSection) *anchorSection = plex->anchorSection; 10305 if (anchorIS) *anchorIS = plex->anchorIS; 10306 PetscFunctionReturn(PETSC_SUCCESS); 10307 } 10308 10309 /*@ 10310 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10311 10312 Collective 10313 10314 Input Parameters: 10315 + dm - The `DMPLEX` object 10316 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10317 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10318 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10319 10320 Level: intermediate 10321 10322 Notes: 10323 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10324 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10325 combination of other points' degrees of freedom. 10326 10327 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10328 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10329 10330 The reference counts of `anchorSection` and `anchorIS` are incremented. 10331 10332 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10333 @*/ 10334 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10335 { 10336 DM_Plex *plex = (DM_Plex *)dm->data; 10337 PetscMPIInt result; 10338 10339 PetscFunctionBegin; 10340 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10341 if (anchorSection) { 10342 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10343 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10344 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10345 } 10346 if (anchorIS) { 10347 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10348 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10349 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10350 } 10351 10352 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10353 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10354 plex->anchorSection = anchorSection; 10355 10356 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10357 PetscCall(ISDestroy(&plex->anchorIS)); 10358 plex->anchorIS = anchorIS; 10359 10360 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10361 PetscInt size, a, pStart, pEnd; 10362 const PetscInt *anchors; 10363 10364 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10365 PetscCall(ISGetLocalSize(anchorIS, &size)); 10366 PetscCall(ISGetIndices(anchorIS, &anchors)); 10367 for (a = 0; a < size; a++) { 10368 PetscInt p; 10369 10370 p = anchors[a]; 10371 if (p >= pStart && p < pEnd) { 10372 PetscInt dof; 10373 10374 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10375 if (dof) { 10376 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10377 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10378 } 10379 } 10380 } 10381 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10382 } 10383 /* reset the generic constraints */ 10384 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10385 PetscFunctionReturn(PETSC_SUCCESS); 10386 } 10387 10388 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10389 { 10390 PetscSection anchorSection; 10391 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10392 10393 PetscFunctionBegin; 10394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10395 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10396 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10397 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10398 if (numFields) { 10399 PetscInt f; 10400 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10401 10402 for (f = 0; f < numFields; f++) { 10403 PetscInt numComp; 10404 10405 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10406 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10407 } 10408 } 10409 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10410 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10411 pStart = PetscMax(pStart, sStart); 10412 pEnd = PetscMin(pEnd, sEnd); 10413 pEnd = PetscMax(pStart, pEnd); 10414 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10415 for (p = pStart; p < pEnd; p++) { 10416 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10417 if (dof) { 10418 PetscCall(PetscSectionGetDof(section, p, &dof)); 10419 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10420 for (f = 0; f < numFields; f++) { 10421 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10422 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10423 } 10424 } 10425 } 10426 PetscCall(PetscSectionSetUp(*cSec)); 10427 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10428 PetscFunctionReturn(PETSC_SUCCESS); 10429 } 10430 10431 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10432 { 10433 PetscSection aSec; 10434 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10435 const PetscInt *anchors; 10436 PetscInt numFields, f; 10437 IS aIS; 10438 MatType mtype; 10439 PetscBool iscuda, iskokkos; 10440 10441 PetscFunctionBegin; 10442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10443 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10444 PetscCall(PetscSectionGetStorageSize(section, &n)); 10445 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10446 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10447 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10448 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10449 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10450 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10451 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10452 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10453 else mtype = MATSEQAIJ; 10454 PetscCall(MatSetType(*cMat, mtype)); 10455 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10456 PetscCall(ISGetIndices(aIS, &anchors)); 10457 /* cSec will be a subset of aSec and section */ 10458 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10459 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10460 PetscCall(PetscMalloc1(m + 1, &i)); 10461 i[0] = 0; 10462 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10463 for (p = pStart; p < pEnd; p++) { 10464 PetscInt rDof, rOff, r; 10465 10466 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10467 if (!rDof) continue; 10468 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10469 if (numFields) { 10470 for (f = 0; f < numFields; f++) { 10471 annz = 0; 10472 for (r = 0; r < rDof; r++) { 10473 a = anchors[rOff + r]; 10474 if (a < sStart || a >= sEnd) continue; 10475 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10476 annz += aDof; 10477 } 10478 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10479 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10480 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10481 } 10482 } else { 10483 annz = 0; 10484 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10485 for (q = 0; q < dof; q++) { 10486 a = anchors[rOff + q]; 10487 if (a < sStart || a >= sEnd) continue; 10488 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10489 annz += aDof; 10490 } 10491 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10492 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10493 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10494 } 10495 } 10496 nnz = i[m]; 10497 PetscCall(PetscMalloc1(nnz, &j)); 10498 offset = 0; 10499 for (p = pStart; p < pEnd; p++) { 10500 if (numFields) { 10501 for (f = 0; f < numFields; f++) { 10502 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10503 for (q = 0; q < dof; q++) { 10504 PetscInt rDof, rOff, r; 10505 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10506 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10507 for (r = 0; r < rDof; r++) { 10508 PetscInt s; 10509 10510 a = anchors[rOff + r]; 10511 if (a < sStart || a >= sEnd) continue; 10512 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10513 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10514 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10515 } 10516 } 10517 } 10518 } else { 10519 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10520 for (q = 0; q < dof; q++) { 10521 PetscInt rDof, rOff, r; 10522 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10523 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10524 for (r = 0; r < rDof; r++) { 10525 PetscInt s; 10526 10527 a = anchors[rOff + r]; 10528 if (a < sStart || a >= sEnd) continue; 10529 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10530 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10531 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10532 } 10533 } 10534 } 10535 } 10536 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10537 PetscCall(PetscFree(i)); 10538 PetscCall(PetscFree(j)); 10539 PetscCall(ISRestoreIndices(aIS, &anchors)); 10540 PetscFunctionReturn(PETSC_SUCCESS); 10541 } 10542 10543 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10544 { 10545 DM_Plex *plex = (DM_Plex *)dm->data; 10546 PetscSection anchorSection, section, cSec; 10547 Mat cMat; 10548 10549 PetscFunctionBegin; 10550 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10551 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10552 if (anchorSection) { 10553 PetscInt Nf; 10554 10555 PetscCall(DMGetLocalSection(dm, §ion)); 10556 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10557 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10558 PetscCall(DMGetNumFields(dm, &Nf)); 10559 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10560 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10561 PetscCall(PetscSectionDestroy(&cSec)); 10562 PetscCall(MatDestroy(&cMat)); 10563 } 10564 PetscFunctionReturn(PETSC_SUCCESS); 10565 } 10566 10567 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10568 { 10569 IS subis; 10570 PetscSection section, subsection; 10571 10572 PetscFunctionBegin; 10573 PetscCall(DMGetLocalSection(dm, §ion)); 10574 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10575 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10576 /* Create subdomain */ 10577 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10578 /* Create submodel */ 10579 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10580 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10581 PetscCall(DMSetLocalSection(*subdm, subsection)); 10582 PetscCall(PetscSectionDestroy(&subsection)); 10583 PetscCall(DMCopyDisc(dm, *subdm)); 10584 /* Create map from submodel to global model */ 10585 if (is) { 10586 PetscSection sectionGlobal, subsectionGlobal; 10587 IS spIS; 10588 const PetscInt *spmap; 10589 PetscInt *subIndices; 10590 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10591 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10592 10593 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10594 PetscCall(ISGetIndices(spIS, &spmap)); 10595 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10596 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10597 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10598 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10599 for (p = pStart; p < pEnd; ++p) { 10600 PetscInt gdof, pSubSize = 0; 10601 10602 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10603 if (gdof > 0) { 10604 for (f = 0; f < Nf; ++f) { 10605 PetscInt fdof, fcdof; 10606 10607 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10608 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10609 pSubSize += fdof - fcdof; 10610 } 10611 subSize += pSubSize; 10612 if (pSubSize) { 10613 if (bs < 0) { 10614 bs = pSubSize; 10615 } else if (bs != pSubSize) { 10616 /* Layout does not admit a pointwise block size */ 10617 bs = 1; 10618 } 10619 } 10620 } 10621 } 10622 /* Must have same blocksize on all procs (some might have no points) */ 10623 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10624 bsLocal[1] = bs; 10625 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10626 if (bsMinMax[0] != bsMinMax[1]) { 10627 bs = 1; 10628 } else { 10629 bs = bsMinMax[0]; 10630 } 10631 PetscCall(PetscMalloc1(subSize, &subIndices)); 10632 for (p = pStart; p < pEnd; ++p) { 10633 PetscInt gdof, goff; 10634 10635 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10636 if (gdof > 0) { 10637 const PetscInt point = spmap[p]; 10638 10639 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10640 for (f = 0; f < Nf; ++f) { 10641 PetscInt fdof, fcdof, fc, f2, poff = 0; 10642 10643 /* Can get rid of this loop by storing field information in the global section */ 10644 for (f2 = 0; f2 < f; ++f2) { 10645 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10646 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10647 poff += fdof - fcdof; 10648 } 10649 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10650 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10651 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10652 } 10653 } 10654 } 10655 PetscCall(ISRestoreIndices(spIS, &spmap)); 10656 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10657 if (bs > 1) { 10658 /* We need to check that the block size does not come from non-contiguous fields */ 10659 PetscInt i, j, set = 1; 10660 for (i = 0; i < subSize; i += bs) { 10661 for (j = 0; j < bs; ++j) { 10662 if (subIndices[i + j] != subIndices[i] + j) { 10663 set = 0; 10664 break; 10665 } 10666 } 10667 } 10668 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10669 } 10670 /* Attach nullspace */ 10671 for (f = 0; f < Nf; ++f) { 10672 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10673 if ((*subdm)->nullspaceConstructors[f]) break; 10674 } 10675 if (f < Nf) { 10676 MatNullSpace nullSpace; 10677 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10678 10679 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10680 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10681 } 10682 } 10683 PetscFunctionReturn(PETSC_SUCCESS); 10684 } 10685 10686 /*@ 10687 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10688 10689 Input Parameters: 10690 + dm - The `DM` 10691 - dummy - unused argument 10692 10693 Options Database Key: 10694 . -dm_plex_monitor_throughput - Activate the monitor 10695 10696 Level: developer 10697 10698 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10699 @*/ 10700 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10701 { 10702 PetscLogHandler default_handler; 10703 10704 PetscFunctionBegin; 10705 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10706 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10707 if (default_handler) { 10708 PetscLogEvent event; 10709 PetscEventPerfInfo eventInfo; 10710 PetscReal cellRate, flopRate; 10711 PetscInt cStart, cEnd, Nf, N; 10712 const char *name; 10713 10714 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10715 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10716 PetscCall(DMGetNumFields(dm, &Nf)); 10717 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10718 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10719 N = (cEnd - cStart) * Nf * eventInfo.count; 10720 flopRate = eventInfo.flops / eventInfo.time; 10721 cellRate = N / eventInfo.time; 10722 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))); 10723 } else { 10724 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."); 10725 } 10726 PetscFunctionReturn(PETSC_SUCCESS); 10727 } 10728