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 } else if (ishdf5) { 674 #if defined(PETSC_HAVE_HDF5) 675 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 676 #else 677 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 678 #endif 679 } else if (isexodusii) { 680 #if defined(PETSC_HAVE_EXODUSII) 681 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 682 #else 683 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 684 #endif 685 } else { 686 PetscBool isseq; 687 688 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 689 if (isseq) PetscCall(VecView_Seq(v, viewer)); 690 else PetscCall(VecView_MPI(v, viewer)); 691 } 692 PetscFunctionReturn(PETSC_SUCCESS); 693 } 694 695 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 696 { 697 DM dm; 698 MPI_Comm comm; 699 PetscViewerFormat format; 700 Vec v; 701 PetscBool isvtk, ishdf5; 702 703 PetscFunctionBegin; 704 PetscCall(VecGetDM(originalv, &dm)); 705 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 706 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 707 PetscCall(PetscViewerGetFormat(viewer, &format)); 708 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 709 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 710 if (format == PETSC_VIEWER_NATIVE) { 711 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 712 /* this need a better fix */ 713 if (dm->useNatural) { 714 if (dm->sfNatural) { 715 const char *vecname; 716 PetscInt n, nroots; 717 718 PetscCall(VecGetLocalSize(originalv, &n)); 719 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 720 if (n == nroots) { 721 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 722 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 723 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 724 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 725 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 726 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 727 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 728 } else v = originalv; 729 } else v = originalv; 730 731 if (ishdf5) { 732 #if defined(PETSC_HAVE_HDF5) 733 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 734 #else 735 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 736 #endif 737 } else if (isvtk) { 738 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 739 } else { 740 PetscBool isseq; 741 742 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 743 if (isseq) PetscCall(VecView_Seq(v, viewer)); 744 else PetscCall(VecView_MPI(v, viewer)); 745 } 746 if (v != originalv) PetscCall(VecDestroy(&v)); 747 PetscFunctionReturn(PETSC_SUCCESS); 748 } 749 750 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 751 { 752 DM dm; 753 PetscBool ishdf5; 754 755 PetscFunctionBegin; 756 PetscCall(VecGetDM(v, &dm)); 757 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 758 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 759 if (ishdf5) { 760 DM dmBC; 761 Vec gv; 762 const char *name; 763 764 PetscCall(DMGetOutputDM(dm, &dmBC)); 765 PetscCall(DMGetGlobalVector(dmBC, &gv)); 766 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 767 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 768 PetscCall(VecLoad_Default(gv, viewer)); 769 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 770 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 771 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 772 } else PetscCall(VecLoad_Default(v, viewer)); 773 PetscFunctionReturn(PETSC_SUCCESS); 774 } 775 776 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 777 { 778 DM dm; 779 PetscBool ishdf5, isexodusii; 780 781 PetscFunctionBegin; 782 PetscCall(VecGetDM(v, &dm)); 783 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 784 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 785 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 786 if (ishdf5) { 787 #if defined(PETSC_HAVE_HDF5) 788 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 789 #else 790 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 791 #endif 792 } else if (isexodusii) { 793 #if defined(PETSC_HAVE_EXODUSII) 794 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 795 #else 796 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 797 #endif 798 } else PetscCall(VecLoad_Default(v, viewer)); 799 PetscFunctionReturn(PETSC_SUCCESS); 800 } 801 802 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 803 { 804 DM dm; 805 PetscViewerFormat format; 806 PetscBool ishdf5; 807 808 PetscFunctionBegin; 809 PetscCall(VecGetDM(originalv, &dm)); 810 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 811 PetscCall(PetscViewerGetFormat(viewer, &format)); 812 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 813 if (format == PETSC_VIEWER_NATIVE) { 814 if (dm->useNatural) { 815 if (dm->sfNatural) { 816 if (ishdf5) { 817 #if defined(PETSC_HAVE_HDF5) 818 Vec v; 819 const char *vecname; 820 821 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 822 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 823 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 824 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 825 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 826 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 827 PetscCall(VecDestroy(&v)); 828 #else 829 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 830 #endif 831 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 832 } 833 } else PetscCall(VecLoad_Default(originalv, viewer)); 834 } 835 PetscFunctionReturn(PETSC_SUCCESS); 836 } 837 838 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 839 { 840 PetscSection coordSection; 841 Vec coordinates; 842 DMLabel depthLabel, celltypeLabel; 843 const char *name[4]; 844 const PetscScalar *a; 845 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 846 847 PetscFunctionBegin; 848 PetscCall(DMGetDimension(dm, &dim)); 849 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 850 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 851 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 852 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 853 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 854 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 855 PetscCall(VecGetArrayRead(coordinates, &a)); 856 name[0] = "vertex"; 857 name[1] = "edge"; 858 name[dim - 1] = "face"; 859 name[dim] = "cell"; 860 for (c = cStart; c < cEnd; ++c) { 861 PetscInt *closure = NULL; 862 PetscInt closureSize, cl, ct; 863 864 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 865 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 866 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 867 PetscCall(PetscViewerASCIIPushTab(viewer)); 868 for (cl = 0; cl < closureSize * 2; cl += 2) { 869 PetscInt point = closure[cl], depth, dof, off, d, p; 870 871 if ((point < pStart) || (point >= pEnd)) continue; 872 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 873 if (!dof) continue; 874 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 875 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 876 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 877 for (p = 0; p < dof / dim; ++p) { 878 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 879 for (d = 0; d < dim; ++d) { 880 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 881 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 882 } 883 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 884 } 885 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 886 } 887 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 888 PetscCall(PetscViewerASCIIPopTab(viewer)); 889 } 890 PetscCall(VecRestoreArrayRead(coordinates, &a)); 891 PetscFunctionReturn(PETSC_SUCCESS); 892 } 893 894 typedef enum { 895 CS_CARTESIAN, 896 CS_POLAR, 897 CS_CYLINDRICAL, 898 CS_SPHERICAL 899 } CoordSystem; 900 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 901 902 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 903 { 904 PetscInt i; 905 906 PetscFunctionBegin; 907 if (dim > 3) { 908 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 909 } else { 910 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 911 912 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 913 switch (cs) { 914 case CS_CARTESIAN: 915 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 916 break; 917 case CS_POLAR: 918 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 919 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 920 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 921 break; 922 case CS_CYLINDRICAL: 923 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 924 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 925 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 926 trcoords[2] = coords[2]; 927 break; 928 case CS_SPHERICAL: 929 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 930 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 931 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 932 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 933 break; 934 } 935 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 936 } 937 PetscFunctionReturn(PETSC_SUCCESS); 938 } 939 940 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 941 { 942 DM_Plex *mesh = (DM_Plex *)dm->data; 943 DM cdm, cdmCell; 944 PetscSection coordSection, coordSectionCell; 945 Vec coordinates, coordinatesCell; 946 PetscViewerFormat format; 947 948 PetscFunctionBegin; 949 PetscCall(PetscViewerGetFormat(viewer, &format)); 950 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 951 const char *name; 952 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 953 PetscInt pStart, pEnd, p, numLabels, l; 954 PetscMPIInt rank, size; 955 956 PetscCall(DMGetCoordinateDM(dm, &cdm)); 957 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 958 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 959 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 960 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 961 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 962 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 963 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 964 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 965 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 966 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 967 PetscCall(DMGetDimension(dm, &dim)); 968 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 969 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 970 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 971 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 972 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 973 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 974 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 975 for (p = pStart; p < pEnd; ++p) { 976 PetscInt dof, off, s; 977 978 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 979 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 980 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 981 } 982 PetscCall(PetscViewerFlush(viewer)); 983 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 984 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 985 for (p = pStart; p < pEnd; ++p) { 986 PetscInt dof, off, c; 987 988 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 989 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 990 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])); 991 } 992 PetscCall(PetscViewerFlush(viewer)); 993 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 994 if (coordSection && coordinates) { 995 CoordSystem cs = CS_CARTESIAN; 996 const PetscScalar *array, *arrayCell = NULL; 997 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 998 PetscMPIInt rank; 999 const char *name; 1000 1001 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1002 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1003 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1004 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1005 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1006 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1007 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1008 pStart = PetscMin(pvStart, pcStart); 1009 pEnd = PetscMax(pvEnd, pcEnd); 1010 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1011 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1012 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1013 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1014 1015 PetscCall(VecGetArrayRead(coordinates, &array)); 1016 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1017 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1018 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1019 for (p = pStart; p < pEnd; ++p) { 1020 PetscInt dof, off; 1021 1022 if (p >= pvStart && p < pvEnd) { 1023 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1024 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1025 if (dof) { 1026 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1027 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1028 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1029 } 1030 } 1031 if (cdmCell && p >= pcStart && p < pcEnd) { 1032 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1033 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1034 if (dof) { 1035 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1036 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1037 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1038 } 1039 } 1040 } 1041 PetscCall(PetscViewerFlush(viewer)); 1042 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1043 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1044 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1045 } 1046 PetscCall(DMGetNumLabels(dm, &numLabels)); 1047 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1048 for (l = 0; l < numLabels; ++l) { 1049 DMLabel label; 1050 PetscBool isdepth; 1051 const char *name; 1052 1053 PetscCall(DMGetLabelName(dm, l, &name)); 1054 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1055 if (isdepth) continue; 1056 PetscCall(DMGetLabel(dm, name, &label)); 1057 PetscCall(DMLabelView(label, viewer)); 1058 } 1059 if (size > 1) { 1060 PetscSF sf; 1061 1062 PetscCall(DMGetPointSF(dm, &sf)); 1063 PetscCall(PetscSFView(sf, viewer)); 1064 } 1065 if (mesh->periodic.face_sfs) 1066 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1067 PetscCall(PetscViewerFlush(viewer)); 1068 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1069 const char *name, *color; 1070 const char *defcolors[3] = {"gray", "orange", "green"}; 1071 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1072 char lname[PETSC_MAX_PATH_LEN]; 1073 PetscReal scale = 2.0; 1074 PetscReal tikzscale = 1.0; 1075 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1076 double tcoords[3]; 1077 PetscScalar *coords; 1078 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; 1079 PetscMPIInt rank, size; 1080 char **names, **colors, **lcolors; 1081 PetscBool flg, lflg; 1082 PetscBT wp = NULL; 1083 PetscInt pEnd, pStart; 1084 1085 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1086 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1087 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1088 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1089 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1090 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1091 PetscCall(DMGetDimension(dm, &dim)); 1092 PetscCall(DMPlexGetDepth(dm, &depth)); 1093 PetscCall(DMGetNumLabels(dm, &numLabels)); 1094 numLabels = PetscMax(numLabels, 10); 1095 numColors = 10; 1096 numLColors = 10; 1097 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1098 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1099 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1100 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1101 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1102 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1103 n = 4; 1104 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1105 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1106 n = 4; 1107 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1108 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1109 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1110 if (!useLabels) numLabels = 0; 1111 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1112 if (!useColors) { 1113 numColors = 3; 1114 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1115 } 1116 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1117 if (!useColors) { 1118 numLColors = 4; 1119 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1120 } 1121 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1122 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1123 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1124 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1125 if (depth < dim) plotEdges = PETSC_FALSE; 1126 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1127 1128 /* filter points with labelvalue != labeldefaultvalue */ 1129 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1130 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1131 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1132 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1133 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1134 if (lflg) { 1135 DMLabel lbl; 1136 1137 PetscCall(DMGetLabel(dm, lname, &lbl)); 1138 if (lbl) { 1139 PetscInt val, defval; 1140 1141 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1142 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1143 for (c = pStart; c < pEnd; c++) { 1144 PetscInt *closure = NULL; 1145 PetscInt closureSize; 1146 1147 PetscCall(DMLabelGetValue(lbl, c, &val)); 1148 if (val == defval) continue; 1149 1150 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1151 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1152 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1153 } 1154 } 1155 } 1156 1157 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1158 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1159 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1161 \\documentclass[tikz]{standalone}\n\n\ 1162 \\usepackage{pgflibraryshapes}\n\ 1163 \\usetikzlibrary{backgrounds}\n\ 1164 \\usetikzlibrary{arrows}\n\ 1165 \\begin{document}\n")); 1166 if (size > 1) { 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1168 for (p = 0; p < size; ++p) { 1169 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1171 } 1172 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1173 } 1174 if (drawHasse) { 1175 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1176 1177 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1178 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1179 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1180 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1181 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1182 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1183 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1184 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1185 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1186 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1187 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1188 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1189 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1190 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1191 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1192 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1193 } 1194 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1195 1196 /* Plot vertices */ 1197 PetscCall(VecGetArray(coordinates, &coords)); 1198 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1199 for (v = vStart; v < vEnd; ++v) { 1200 PetscInt off, dof, d; 1201 PetscBool isLabeled = PETSC_FALSE; 1202 1203 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1204 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1205 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1207 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1208 for (d = 0; d < dof; ++d) { 1209 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1210 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1211 } 1212 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1213 if (dim == 3) { 1214 PetscReal tmp = tcoords[1]; 1215 tcoords[1] = tcoords[2]; 1216 tcoords[2] = -tmp; 1217 } 1218 for (d = 0; d < dof; ++d) { 1219 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1220 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1221 } 1222 if (drawHasse) color = colors[0 % numColors]; 1223 else color = colors[rank % numColors]; 1224 for (l = 0; l < numLabels; ++l) { 1225 PetscInt val; 1226 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1227 if (val >= 0) { 1228 color = lcolors[l % numLColors]; 1229 isLabeled = PETSC_TRUE; 1230 break; 1231 } 1232 } 1233 if (drawNumbers[0]) { 1234 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1235 } else if (drawColors[0]) { 1236 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1237 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1238 } 1239 PetscCall(VecRestoreArray(coordinates, &coords)); 1240 PetscCall(PetscViewerFlush(viewer)); 1241 /* Plot edges */ 1242 if (plotEdges) { 1243 PetscCall(VecGetArray(coordinates, &coords)); 1244 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1245 for (e = eStart; e < eEnd; ++e) { 1246 const PetscInt *cone; 1247 PetscInt coneSize, offA, offB, dof, d; 1248 1249 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1250 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1251 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1252 PetscCall(DMPlexGetCone(dm, e, &cone)); 1253 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1254 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1255 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1256 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1257 for (d = 0; d < dof; ++d) { 1258 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1259 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1260 } 1261 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1262 if (dim == 3) { 1263 PetscReal tmp = tcoords[1]; 1264 tcoords[1] = tcoords[2]; 1265 tcoords[2] = -tmp; 1266 } 1267 for (d = 0; d < dof; ++d) { 1268 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1269 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1270 } 1271 if (drawHasse) color = colors[1 % numColors]; 1272 else color = colors[rank % numColors]; 1273 for (l = 0; l < numLabels; ++l) { 1274 PetscInt val; 1275 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1276 if (val >= 0) { 1277 color = lcolors[l % numLColors]; 1278 break; 1279 } 1280 } 1281 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1282 } 1283 PetscCall(VecRestoreArray(coordinates, &coords)); 1284 PetscCall(PetscViewerFlush(viewer)); 1285 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1286 } 1287 /* Plot cells */ 1288 if (dim == 3 || !drawNumbers[1]) { 1289 for (e = eStart; e < eEnd; ++e) { 1290 const PetscInt *cone; 1291 1292 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1293 color = colors[rank % numColors]; 1294 for (l = 0; l < numLabels; ++l) { 1295 PetscInt val; 1296 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1297 if (val >= 0) { 1298 color = lcolors[l % numLColors]; 1299 break; 1300 } 1301 } 1302 PetscCall(DMPlexGetCone(dm, e, &cone)); 1303 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1304 } 1305 } else { 1306 DMPolytopeType ct; 1307 1308 /* Drawing a 2D polygon */ 1309 for (c = cStart; c < cEnd; ++c) { 1310 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1311 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1312 if (DMPolytopeTypeIsHybrid(ct)) { 1313 const PetscInt *cone; 1314 PetscInt coneSize, e; 1315 1316 PetscCall(DMPlexGetCone(dm, c, &cone)); 1317 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1318 for (e = 0; e < coneSize; ++e) { 1319 const PetscInt *econe; 1320 1321 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1322 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)); 1323 } 1324 } else { 1325 PetscInt *closure = NULL; 1326 PetscInt closureSize, Nv = 0, v; 1327 1328 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1329 for (p = 0; p < closureSize * 2; p += 2) { 1330 const PetscInt point = closure[p]; 1331 1332 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1333 } 1334 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1335 for (v = 0; v <= Nv; ++v) { 1336 const PetscInt vertex = closure[v % Nv]; 1337 1338 if (v > 0) { 1339 if (plotEdges) { 1340 const PetscInt *edge; 1341 PetscInt endpoints[2], ne; 1342 1343 endpoints[0] = closure[v - 1]; 1344 endpoints[1] = vertex; 1345 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1346 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1347 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1348 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1349 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1350 } 1351 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1352 } 1353 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1354 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1355 } 1356 } 1357 } 1358 for (c = cStart; c < cEnd; ++c) { 1359 double ccoords[3] = {0.0, 0.0, 0.0}; 1360 PetscBool isLabeled = PETSC_FALSE; 1361 PetscScalar *cellCoords = NULL; 1362 const PetscScalar *array; 1363 PetscInt numCoords, cdim, d; 1364 PetscBool isDG; 1365 1366 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1367 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1368 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1369 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1370 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1371 for (p = 0; p < numCoords / cdim; ++p) { 1372 for (d = 0; d < cdim; ++d) { 1373 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1374 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1375 } 1376 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1377 if (cdim == 3) { 1378 PetscReal tmp = tcoords[1]; 1379 tcoords[1] = tcoords[2]; 1380 tcoords[2] = -tmp; 1381 } 1382 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1383 } 1384 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1385 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1386 for (d = 0; d < cdim; ++d) { 1387 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1388 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1389 } 1390 if (drawHasse) color = colors[depth % numColors]; 1391 else color = colors[rank % numColors]; 1392 for (l = 0; l < numLabels; ++l) { 1393 PetscInt val; 1394 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1395 if (val >= 0) { 1396 color = lcolors[l % numLColors]; 1397 isLabeled = PETSC_TRUE; 1398 break; 1399 } 1400 } 1401 if (drawNumbers[dim]) { 1402 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1403 } else if (drawColors[dim]) { 1404 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1405 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1406 } 1407 if (drawHasse) { 1408 int height = 0; 1409 1410 color = colors[depth % numColors]; 1411 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1412 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1413 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1414 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1416 1417 if (depth > 2) { 1418 color = colors[1 % numColors]; 1419 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1420 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1421 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1422 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1424 } 1425 1426 color = colors[1 % numColors]; 1427 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1428 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1429 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1430 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1431 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1432 1433 color = colors[0 % numColors]; 1434 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1435 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1436 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1437 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1438 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1439 1440 for (p = pStart; p < pEnd; ++p) { 1441 const PetscInt *cone; 1442 PetscInt coneSize, cp; 1443 1444 PetscCall(DMPlexGetCone(dm, p, &cone)); 1445 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1446 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1447 } 1448 } 1449 PetscCall(PetscViewerFlush(viewer)); 1450 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1451 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1452 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1453 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1454 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1455 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1456 PetscCall(PetscFree3(names, colors, lcolors)); 1457 PetscCall(PetscBTDestroy(&wp)); 1458 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1459 Vec cown, acown; 1460 VecScatter sct; 1461 ISLocalToGlobalMapping g2l; 1462 IS gid, acis; 1463 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1464 MPI_Group ggroup, ngroup; 1465 PetscScalar *array, nid; 1466 const PetscInt *idxs; 1467 PetscInt *idxs2, *start, *adjacency, *work; 1468 PetscInt64 lm[3], gm[3]; 1469 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1470 PetscMPIInt d1, d2, rank; 1471 1472 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1473 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1474 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1475 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1476 #endif 1477 if (ncomm != MPI_COMM_NULL) { 1478 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1479 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1480 d1 = 0; 1481 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1482 nid = d2; 1483 PetscCallMPI(MPI_Group_free(&ggroup)); 1484 PetscCallMPI(MPI_Group_free(&ngroup)); 1485 PetscCallMPI(MPI_Comm_free(&ncomm)); 1486 } else nid = 0.0; 1487 1488 /* Get connectivity */ 1489 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1490 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1491 1492 /* filter overlapped local cells */ 1493 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1494 PetscCall(ISGetIndices(gid, &idxs)); 1495 PetscCall(ISGetLocalSize(gid, &cum)); 1496 PetscCall(PetscMalloc1(cum, &idxs2)); 1497 for (c = cStart, cum = 0; c < cEnd; c++) { 1498 if (idxs[c - cStart] < 0) continue; 1499 idxs2[cum++] = idxs[c - cStart]; 1500 } 1501 PetscCall(ISRestoreIndices(gid, &idxs)); 1502 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1503 PetscCall(ISDestroy(&gid)); 1504 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1505 1506 /* support for node-aware cell locality */ 1507 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1508 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1509 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1510 PetscCall(VecGetArray(cown, &array)); 1511 for (c = 0; c < numVertices; c++) array[c] = nid; 1512 PetscCall(VecRestoreArray(cown, &array)); 1513 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1514 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1515 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1516 PetscCall(ISDestroy(&acis)); 1517 PetscCall(VecScatterDestroy(&sct)); 1518 PetscCall(VecDestroy(&cown)); 1519 1520 /* compute edgeCut */ 1521 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1522 PetscCall(PetscMalloc1(cum, &work)); 1523 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1524 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1525 PetscCall(ISDestroy(&gid)); 1526 PetscCall(VecGetArray(acown, &array)); 1527 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1528 PetscInt totl; 1529 1530 totl = start[c + 1] - start[c]; 1531 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1532 for (i = 0; i < totl; i++) { 1533 if (work[i] < 0) { 1534 ect += 1; 1535 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1536 } 1537 } 1538 } 1539 PetscCall(PetscFree(work)); 1540 PetscCall(VecRestoreArray(acown, &array)); 1541 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1542 lm[1] = -numVertices; 1543 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1544 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1545 lm[0] = ect; /* edgeCut */ 1546 lm[1] = ectn; /* node-aware edgeCut */ 1547 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1548 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1549 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1550 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1551 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1552 #else 1553 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1554 #endif 1555 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1556 PetscCall(PetscFree(start)); 1557 PetscCall(PetscFree(adjacency)); 1558 PetscCall(VecDestroy(&acown)); 1559 } else { 1560 const char *name; 1561 PetscInt *sizes, *hybsizes, *ghostsizes; 1562 PetscInt locDepth, depth, cellHeight, dim, d; 1563 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1564 PetscInt numLabels, l, maxSize = 17; 1565 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1566 MPI_Comm comm; 1567 PetscMPIInt size, rank; 1568 1569 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1570 PetscCallMPI(MPI_Comm_size(comm, &size)); 1571 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1572 PetscCall(DMGetDimension(dm, &dim)); 1573 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1574 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1575 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1576 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1577 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1578 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1579 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1580 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1581 gcNum = gcEnd - gcStart; 1582 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1583 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1584 for (d = 0; d <= depth; d++) { 1585 PetscInt Nc[2] = {0, 0}, ict; 1586 1587 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1588 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1589 ict = ct0; 1590 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1591 ct0 = (DMPolytopeType)ict; 1592 for (p = pStart; p < pEnd; ++p) { 1593 DMPolytopeType ct; 1594 1595 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1596 if (ct == ct0) ++Nc[0]; 1597 else ++Nc[1]; 1598 } 1599 if (size < maxSize) { 1600 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1601 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1602 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1603 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1604 for (p = 0; p < size; ++p) { 1605 if (rank == 0) { 1606 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1607 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1608 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1609 } 1610 } 1611 } else { 1612 PetscInt locMinMax[2]; 1613 1614 locMinMax[0] = Nc[0] + Nc[1]; 1615 locMinMax[1] = Nc[0] + Nc[1]; 1616 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1617 locMinMax[0] = Nc[1]; 1618 locMinMax[1] = Nc[1]; 1619 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1620 if (d == depth) { 1621 locMinMax[0] = gcNum; 1622 locMinMax[1] = gcNum; 1623 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1624 } 1625 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1626 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1627 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1628 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1629 } 1630 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1631 } 1632 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1633 { 1634 const PetscReal *maxCell; 1635 const PetscReal *L; 1636 PetscBool localized; 1637 1638 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1639 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1640 if (L || localized) { 1641 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1642 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1643 if (L) { 1644 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1645 for (d = 0; d < dim; ++d) { 1646 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1647 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1648 } 1649 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1650 } 1651 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1652 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1653 } 1654 } 1655 PetscCall(DMGetNumLabels(dm, &numLabels)); 1656 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1657 for (l = 0; l < numLabels; ++l) { 1658 DMLabel label; 1659 const char *name; 1660 PetscInt *values; 1661 PetscInt numValues, v; 1662 1663 PetscCall(DMGetLabelName(dm, l, &name)); 1664 PetscCall(DMGetLabel(dm, name, &label)); 1665 PetscCall(DMLabelGetNumValues(label, &numValues)); 1666 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1667 1668 { // Extract array of DMLabel values so it can be sorted 1669 IS is_values; 1670 const PetscInt *is_values_local = NULL; 1671 1672 PetscCall(DMLabelGetValueIS(label, &is_values)); 1673 PetscCall(ISGetIndices(is_values, &is_values_local)); 1674 PetscCall(PetscMalloc1(numValues, &values)); 1675 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1676 PetscCall(PetscSortInt(numValues, values)); 1677 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1678 PetscCall(ISDestroy(&is_values)); 1679 } 1680 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1681 for (v = 0; v < numValues; ++v) { 1682 PetscInt size; 1683 1684 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1685 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1686 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1687 } 1688 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1689 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1690 PetscCall(PetscFree(values)); 1691 } 1692 { 1693 char **labelNames; 1694 PetscInt Nl = numLabels; 1695 PetscBool flg; 1696 1697 PetscCall(PetscMalloc1(Nl, &labelNames)); 1698 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1699 for (l = 0; l < Nl; ++l) { 1700 DMLabel label; 1701 1702 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1703 if (flg) { 1704 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1705 PetscCall(DMLabelView(label, viewer)); 1706 } 1707 PetscCall(PetscFree(labelNames[l])); 1708 } 1709 PetscCall(PetscFree(labelNames)); 1710 } 1711 /* If no fields are specified, people do not want to see adjacency */ 1712 if (dm->Nf) { 1713 PetscInt f; 1714 1715 for (f = 0; f < dm->Nf; ++f) { 1716 const char *name; 1717 1718 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1719 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1720 PetscCall(PetscViewerASCIIPushTab(viewer)); 1721 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1722 if (dm->fields[f].adjacency[0]) { 1723 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1724 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1725 } else { 1726 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1727 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1728 } 1729 PetscCall(PetscViewerASCIIPopTab(viewer)); 1730 } 1731 } 1732 PetscCall(DMGetCoarseDM(dm, &cdm)); 1733 if (cdm) { 1734 PetscCall(PetscViewerASCIIPushTab(viewer)); 1735 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1736 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1737 PetscCall(PetscViewerASCIIPopTab(viewer)); 1738 } 1739 } 1740 PetscFunctionReturn(PETSC_SUCCESS); 1741 } 1742 1743 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1744 { 1745 DMPolytopeType ct; 1746 PetscMPIInt rank; 1747 PetscInt cdim; 1748 1749 PetscFunctionBegin; 1750 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1751 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1752 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1753 switch (ct) { 1754 case DM_POLYTOPE_SEGMENT: 1755 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1756 switch (cdim) { 1757 case 1: { 1758 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1759 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1760 1761 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1762 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1763 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1764 } break; 1765 case 2: { 1766 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1767 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1768 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1769 1770 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1771 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1772 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)); 1773 } break; 1774 default: 1775 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1776 } 1777 break; 1778 case DM_POLYTOPE_TRIANGLE: 1779 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)); 1780 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1781 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1782 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1783 break; 1784 case DM_POLYTOPE_QUADRILATERAL: 1785 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)); 1786 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)); 1787 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1788 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1789 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1790 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1791 break; 1792 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1793 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)); 1794 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)); 1795 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1796 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1797 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1798 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1799 break; 1800 case DM_POLYTOPE_FV_GHOST: 1801 break; 1802 default: 1803 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1804 } 1805 PetscFunctionReturn(PETSC_SUCCESS); 1806 } 1807 1808 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1809 { 1810 PetscReal centroid[2] = {0., 0.}; 1811 PetscMPIInt rank; 1812 PetscInt fillColor; 1813 1814 PetscFunctionBegin; 1815 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1816 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1817 for (PetscInt v = 0; v < Nv; ++v) { 1818 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1819 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1820 } 1821 for (PetscInt e = 0; e < Nv; ++e) { 1822 refCoords[0] = refVertices[e * 2 + 0]; 1823 refCoords[1] = refVertices[e * 2 + 1]; 1824 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1825 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1826 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1827 } 1828 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1829 for (PetscInt d = 0; d < edgeDiv; ++d) { 1830 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)); 1831 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1832 } 1833 } 1834 PetscFunctionReturn(PETSC_SUCCESS); 1835 } 1836 1837 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1838 { 1839 DMPolytopeType ct; 1840 1841 PetscFunctionBegin; 1842 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1843 switch (ct) { 1844 case DM_POLYTOPE_TRIANGLE: { 1845 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1846 1847 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1848 } break; 1849 case DM_POLYTOPE_QUADRILATERAL: { 1850 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1851 1852 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1853 } break; 1854 default: 1855 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1856 } 1857 PetscFunctionReturn(PETSC_SUCCESS); 1858 } 1859 1860 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1861 { 1862 PetscDraw draw; 1863 DM cdm; 1864 PetscSection coordSection; 1865 Vec coordinates; 1866 PetscReal xyl[3], xyr[3]; 1867 PetscReal *refCoords, *edgeCoords; 1868 PetscBool isnull, drawAffine; 1869 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1870 1871 PetscFunctionBegin; 1872 PetscCall(DMGetCoordinateDim(dm, &dim)); 1873 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1874 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1875 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1876 edgeDiv = cDegree + 1; 1877 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1878 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1879 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1880 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1881 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1882 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1883 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1884 1885 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1886 PetscCall(PetscDrawIsNull(draw, &isnull)); 1887 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1888 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1889 1890 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1891 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1892 PetscCall(PetscDrawClear(draw)); 1893 1894 for (c = cStart; c < cEnd; ++c) { 1895 PetscScalar *coords = NULL; 1896 const PetscScalar *coords_arr; 1897 PetscInt numCoords; 1898 PetscBool isDG; 1899 1900 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1901 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1902 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1903 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1904 } 1905 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1906 PetscCall(PetscDrawFlush(draw)); 1907 PetscCall(PetscDrawPause(draw)); 1908 PetscCall(PetscDrawSave(draw)); 1909 PetscFunctionReturn(PETSC_SUCCESS); 1910 } 1911 1912 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1913 { 1914 DM odm = dm, rdm = dm, cdm; 1915 PetscFE fe; 1916 PetscSpace sp; 1917 PetscClassId id; 1918 PetscInt degree; 1919 PetscBool hoView = PETSC_TRUE; 1920 1921 PetscFunctionBegin; 1922 PetscObjectOptionsBegin((PetscObject)dm); 1923 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1924 PetscOptionsEnd(); 1925 PetscCall(PetscObjectReference((PetscObject)dm)); 1926 *hdm = dm; 1927 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1928 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1929 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1930 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1931 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1932 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1933 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1934 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1935 DM cdm, rcdm; 1936 Mat In; 1937 Vec cl, rcl; 1938 1939 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1940 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1941 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1942 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1943 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1944 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1945 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1946 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1947 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1948 PetscCall(MatMult(In, cl, rcl)); 1949 PetscCall(MatDestroy(&In)); 1950 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1951 PetscCall(DMDestroy(&odm)); 1952 odm = rdm; 1953 } 1954 *hdm = rdm; 1955 PetscFunctionReturn(PETSC_SUCCESS); 1956 } 1957 1958 #if defined(PETSC_HAVE_EXODUSII) 1959 #include <exodusII.h> 1960 #include <petscviewerexodusii.h> 1961 #endif 1962 1963 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1964 { 1965 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1966 char name[PETSC_MAX_PATH_LEN]; 1967 1968 PetscFunctionBegin; 1969 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1970 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1971 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1972 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1973 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1974 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1975 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1976 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1977 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1978 if (iascii) { 1979 PetscViewerFormat format; 1980 PetscCall(PetscViewerGetFormat(viewer, &format)); 1981 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1982 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1983 } else if (ishdf5) { 1984 #if defined(PETSC_HAVE_HDF5) 1985 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1986 #else 1987 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1988 #endif 1989 } else if (isvtk) { 1990 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1991 } else if (isdraw) { 1992 DM hdm; 1993 1994 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1995 PetscCall(DMPlexView_Draw(hdm, viewer)); 1996 PetscCall(DMDestroy(&hdm)); 1997 } else if (isglvis) { 1998 PetscCall(DMPlexView_GLVis(dm, viewer)); 1999 #if defined(PETSC_HAVE_EXODUSII) 2000 } else if (isexodus) { 2001 /* 2002 exodusII requires that all sets be part of exactly one cell set. 2003 If the dm does not have a "Cell Sets" label defined, we create one 2004 with ID 1, containing all cells. 2005 Note that if the Cell Sets label is defined but does not cover all cells, 2006 we may still have a problem. This should probably be checked here or in the viewer; 2007 */ 2008 PetscInt numCS; 2009 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2010 if (!numCS) { 2011 PetscInt cStart, cEnd, c; 2012 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2013 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2014 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2015 } 2016 PetscCall(DMView_PlexExodusII(dm, viewer)); 2017 #endif 2018 #if defined(PETSC_HAVE_CGNS) 2019 } else if (iscgns) { 2020 PetscCall(DMView_PlexCGNS(dm, viewer)); 2021 #endif 2022 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2023 /* Optionally view the partition */ 2024 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2025 if (flg) { 2026 Vec ranks; 2027 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2028 PetscCall(VecView(ranks, viewer)); 2029 PetscCall(VecDestroy(&ranks)); 2030 } 2031 /* Optionally view a label */ 2032 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2033 if (flg) { 2034 DMLabel label; 2035 Vec val; 2036 2037 PetscCall(DMGetLabel(dm, name, &label)); 2038 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2039 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2040 PetscCall(VecView(val, viewer)); 2041 PetscCall(VecDestroy(&val)); 2042 } 2043 PetscFunctionReturn(PETSC_SUCCESS); 2044 } 2045 2046 /*@ 2047 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2048 2049 Collective 2050 2051 Input Parameters: 2052 + dm - The `DM` whose topology is to be saved 2053 - viewer - The `PetscViewer` to save it in 2054 2055 Level: advanced 2056 2057 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2058 @*/ 2059 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2060 { 2061 PetscBool ishdf5; 2062 2063 PetscFunctionBegin; 2064 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2065 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2066 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2067 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2068 if (ishdf5) { 2069 #if defined(PETSC_HAVE_HDF5) 2070 PetscViewerFormat format; 2071 PetscCall(PetscViewerGetFormat(viewer, &format)); 2072 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2073 IS globalPointNumbering; 2074 2075 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2076 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2077 PetscCall(ISDestroy(&globalPointNumbering)); 2078 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2079 #else 2080 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2081 #endif 2082 } 2083 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2084 PetscFunctionReturn(PETSC_SUCCESS); 2085 } 2086 2087 /*@ 2088 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2089 2090 Collective 2091 2092 Input Parameters: 2093 + dm - The `DM` whose coordinates are to be saved 2094 - viewer - The `PetscViewer` for saving 2095 2096 Level: advanced 2097 2098 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2099 @*/ 2100 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2101 { 2102 PetscBool ishdf5; 2103 2104 PetscFunctionBegin; 2105 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2106 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2107 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2108 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2109 if (ishdf5) { 2110 #if defined(PETSC_HAVE_HDF5) 2111 PetscViewerFormat format; 2112 PetscCall(PetscViewerGetFormat(viewer, &format)); 2113 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2114 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2115 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2116 #else 2117 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2118 #endif 2119 } 2120 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2121 PetscFunctionReturn(PETSC_SUCCESS); 2122 } 2123 2124 /*@ 2125 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2126 2127 Collective 2128 2129 Input Parameters: 2130 + dm - The `DM` whose labels are to be saved 2131 - viewer - The `PetscViewer` for saving 2132 2133 Level: advanced 2134 2135 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2136 @*/ 2137 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2138 { 2139 PetscBool ishdf5; 2140 2141 PetscFunctionBegin; 2142 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2143 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2144 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2145 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2146 if (ishdf5) { 2147 #if defined(PETSC_HAVE_HDF5) 2148 IS globalPointNumbering; 2149 PetscViewerFormat format; 2150 2151 PetscCall(PetscViewerGetFormat(viewer, &format)); 2152 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2153 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2154 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2155 PetscCall(ISDestroy(&globalPointNumbering)); 2156 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2157 #else 2158 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2159 #endif 2160 } 2161 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2162 PetscFunctionReturn(PETSC_SUCCESS); 2163 } 2164 2165 /*@ 2166 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2167 2168 Collective 2169 2170 Input Parameters: 2171 + dm - The `DM` that contains the topology on which the section to be saved is defined 2172 . viewer - The `PetscViewer` for saving 2173 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2174 2175 Level: advanced 2176 2177 Notes: 2178 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. 2179 2180 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. 2181 2182 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2183 @*/ 2184 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2185 { 2186 PetscBool ishdf5; 2187 2188 PetscFunctionBegin; 2189 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2190 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2191 if (!sectiondm) sectiondm = dm; 2192 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2193 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2194 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2195 if (ishdf5) { 2196 #if defined(PETSC_HAVE_HDF5) 2197 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2198 #else 2199 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2200 #endif 2201 } 2202 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2203 PetscFunctionReturn(PETSC_SUCCESS); 2204 } 2205 2206 /*@ 2207 DMPlexGlobalVectorView - Saves a global vector 2208 2209 Collective 2210 2211 Input Parameters: 2212 + dm - The `DM` that represents the topology 2213 . viewer - The `PetscViewer` to save data with 2214 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2215 - vec - The global vector to be saved 2216 2217 Level: advanced 2218 2219 Notes: 2220 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. 2221 2222 Calling sequence: 2223 .vb 2224 DMCreate(PETSC_COMM_WORLD, &dm); 2225 DMSetType(dm, DMPLEX); 2226 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2227 DMClone(dm, §iondm); 2228 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2229 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2230 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2231 PetscSectionSetChart(section, pStart, pEnd); 2232 PetscSectionSetUp(section); 2233 DMSetLocalSection(sectiondm, section); 2234 PetscSectionDestroy(§ion); 2235 DMGetGlobalVector(sectiondm, &vec); 2236 PetscObjectSetName((PetscObject)vec, "vec_name"); 2237 DMPlexTopologyView(dm, viewer); 2238 DMPlexSectionView(dm, viewer, sectiondm); 2239 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2240 DMRestoreGlobalVector(sectiondm, &vec); 2241 DMDestroy(§iondm); 2242 DMDestroy(&dm); 2243 .ve 2244 2245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2246 @*/ 2247 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2248 { 2249 PetscBool ishdf5; 2250 2251 PetscFunctionBegin; 2252 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2253 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2254 if (!sectiondm) sectiondm = dm; 2255 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2256 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2257 /* Check consistency */ 2258 { 2259 PetscSection section; 2260 PetscBool includesConstraints; 2261 PetscInt m, m1; 2262 2263 PetscCall(VecGetLocalSize(vec, &m1)); 2264 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2265 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2266 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2267 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2268 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2269 } 2270 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2271 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2272 if (ishdf5) { 2273 #if defined(PETSC_HAVE_HDF5) 2274 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2275 #else 2276 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2277 #endif 2278 } 2279 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2280 PetscFunctionReturn(PETSC_SUCCESS); 2281 } 2282 2283 /*@ 2284 DMPlexLocalVectorView - Saves a local vector 2285 2286 Collective 2287 2288 Input Parameters: 2289 + dm - The `DM` that represents the topology 2290 . viewer - The `PetscViewer` to save data with 2291 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2292 - vec - The local vector to be saved 2293 2294 Level: advanced 2295 2296 Note: 2297 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. 2298 2299 Calling sequence: 2300 .vb 2301 DMCreate(PETSC_COMM_WORLD, &dm); 2302 DMSetType(dm, DMPLEX); 2303 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2304 DMClone(dm, §iondm); 2305 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2306 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2307 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2308 PetscSectionSetChart(section, pStart, pEnd); 2309 PetscSectionSetUp(section); 2310 DMSetLocalSection(sectiondm, section); 2311 DMGetLocalVector(sectiondm, &vec); 2312 PetscObjectSetName((PetscObject)vec, "vec_name"); 2313 DMPlexTopologyView(dm, viewer); 2314 DMPlexSectionView(dm, viewer, sectiondm); 2315 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2316 DMRestoreLocalVector(sectiondm, &vec); 2317 DMDestroy(§iondm); 2318 DMDestroy(&dm); 2319 .ve 2320 2321 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2322 @*/ 2323 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2324 { 2325 PetscBool ishdf5; 2326 2327 PetscFunctionBegin; 2328 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2329 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2330 if (!sectiondm) sectiondm = dm; 2331 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2332 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2333 /* Check consistency */ 2334 { 2335 PetscSection section; 2336 PetscBool includesConstraints; 2337 PetscInt m, m1; 2338 2339 PetscCall(VecGetLocalSize(vec, &m1)); 2340 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2341 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2342 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2343 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2344 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2345 } 2346 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2347 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2348 if (ishdf5) { 2349 #if defined(PETSC_HAVE_HDF5) 2350 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2351 #else 2352 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2353 #endif 2354 } 2355 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2356 PetscFunctionReturn(PETSC_SUCCESS); 2357 } 2358 2359 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2360 { 2361 PetscBool ishdf5; 2362 2363 PetscFunctionBegin; 2364 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2365 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2366 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2367 if (ishdf5) { 2368 #if defined(PETSC_HAVE_HDF5) 2369 PetscViewerFormat format; 2370 PetscCall(PetscViewerGetFormat(viewer, &format)); 2371 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2372 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2373 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2374 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2375 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2376 PetscFunctionReturn(PETSC_SUCCESS); 2377 #else 2378 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2379 #endif 2380 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2381 } 2382 2383 /*@ 2384 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2385 2386 Collective 2387 2388 Input Parameters: 2389 + dm - The `DM` into which the topology is loaded 2390 - viewer - The `PetscViewer` for the saved topology 2391 2392 Output Parameter: 2393 . 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; 2394 `NULL` if unneeded 2395 2396 Level: advanced 2397 2398 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2399 `PetscViewer`, `PetscSF` 2400 @*/ 2401 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2402 { 2403 PetscBool ishdf5; 2404 2405 PetscFunctionBegin; 2406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2407 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2408 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2409 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2410 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2411 if (ishdf5) { 2412 #if defined(PETSC_HAVE_HDF5) 2413 PetscViewerFormat format; 2414 PetscCall(PetscViewerGetFormat(viewer, &format)); 2415 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2416 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2417 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2418 #else 2419 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2420 #endif 2421 } 2422 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2423 PetscFunctionReturn(PETSC_SUCCESS); 2424 } 2425 2426 /*@ 2427 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2428 2429 Collective 2430 2431 Input Parameters: 2432 + dm - The `DM` into which the coordinates are loaded 2433 . viewer - The `PetscViewer` for the saved coordinates 2434 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2435 2436 Level: advanced 2437 2438 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2439 `PetscSF`, `PetscViewer` 2440 @*/ 2441 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2442 { 2443 PetscBool ishdf5; 2444 2445 PetscFunctionBegin; 2446 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2447 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2448 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2449 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2450 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2451 if (ishdf5) { 2452 #if defined(PETSC_HAVE_HDF5) 2453 PetscViewerFormat format; 2454 PetscCall(PetscViewerGetFormat(viewer, &format)); 2455 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2456 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2457 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2458 #else 2459 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2460 #endif 2461 } 2462 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2463 PetscFunctionReturn(PETSC_SUCCESS); 2464 } 2465 2466 /*@ 2467 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2468 2469 Collective 2470 2471 Input Parameters: 2472 + dm - The `DM` into which the labels are loaded 2473 . viewer - The `PetscViewer` for the saved labels 2474 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2475 2476 Level: advanced 2477 2478 Note: 2479 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2480 2481 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2482 `PetscSF`, `PetscViewer` 2483 @*/ 2484 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2485 { 2486 PetscBool ishdf5; 2487 2488 PetscFunctionBegin; 2489 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2490 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2491 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2492 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2493 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2494 if (ishdf5) { 2495 #if defined(PETSC_HAVE_HDF5) 2496 PetscViewerFormat format; 2497 2498 PetscCall(PetscViewerGetFormat(viewer, &format)); 2499 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2500 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2501 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2502 #else 2503 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2504 #endif 2505 } 2506 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2507 PetscFunctionReturn(PETSC_SUCCESS); 2508 } 2509 2510 /*@ 2511 DMPlexSectionLoad - Loads section into a `DMPLEX` 2512 2513 Collective 2514 2515 Input Parameters: 2516 + dm - The `DM` that represents the topology 2517 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2518 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2519 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2520 2521 Output Parameters: 2522 + 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) 2523 - 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) 2524 2525 Level: advanced 2526 2527 Notes: 2528 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. 2529 2530 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. 2531 2532 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. 2533 2534 Example using 2 processes: 2535 .vb 2536 NX (number of points on dm): 4 2537 sectionA : the on-disk section 2538 vecA : a vector associated with sectionA 2539 sectionB : sectiondm's local section constructed in this function 2540 vecB (local) : a vector associated with sectiondm's local section 2541 vecB (global) : a vector associated with sectiondm's global section 2542 2543 rank 0 rank 1 2544 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2545 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2546 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2547 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2548 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2549 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2550 sectionB->atlasDof : 1 0 1 | 1 3 2551 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2552 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2553 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2554 .ve 2555 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2556 2557 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2558 @*/ 2559 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2560 { 2561 PetscBool ishdf5; 2562 2563 PetscFunctionBegin; 2564 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2565 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2566 if (!sectiondm) sectiondm = dm; 2567 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2568 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2569 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2570 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2571 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2572 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2573 if (ishdf5) { 2574 #if defined(PETSC_HAVE_HDF5) 2575 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2576 #else 2577 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2578 #endif 2579 } 2580 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2581 PetscFunctionReturn(PETSC_SUCCESS); 2582 } 2583 2584 /*@ 2585 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2586 2587 Collective 2588 2589 Input Parameters: 2590 + dm - The `DM` that represents the topology 2591 . viewer - The `PetscViewer` that represents the on-disk vector data 2592 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2593 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2594 - vec - The global vector to set values of 2595 2596 Level: advanced 2597 2598 Notes: 2599 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. 2600 2601 Calling sequence: 2602 .vb 2603 DMCreate(PETSC_COMM_WORLD, &dm); 2604 DMSetType(dm, DMPLEX); 2605 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2606 DMPlexTopologyLoad(dm, viewer, &sfX); 2607 DMClone(dm, §iondm); 2608 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2609 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2610 DMGetGlobalVector(sectiondm, &vec); 2611 PetscObjectSetName((PetscObject)vec, "vec_name"); 2612 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2613 DMRestoreGlobalVector(sectiondm, &vec); 2614 PetscSFDestroy(&gsf); 2615 PetscSFDestroy(&sfX); 2616 DMDestroy(§iondm); 2617 DMDestroy(&dm); 2618 .ve 2619 2620 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2621 `PetscSF`, `PetscViewer` 2622 @*/ 2623 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2624 { 2625 PetscBool ishdf5; 2626 2627 PetscFunctionBegin; 2628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2629 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2630 if (!sectiondm) sectiondm = dm; 2631 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2632 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2633 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2634 /* Check consistency */ 2635 { 2636 PetscSection section; 2637 PetscBool includesConstraints; 2638 PetscInt m, m1; 2639 2640 PetscCall(VecGetLocalSize(vec, &m1)); 2641 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2642 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2643 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2644 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2645 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2646 } 2647 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2648 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2649 if (ishdf5) { 2650 #if defined(PETSC_HAVE_HDF5) 2651 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2652 #else 2653 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2654 #endif 2655 } 2656 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2657 PetscFunctionReturn(PETSC_SUCCESS); 2658 } 2659 2660 /*@ 2661 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2662 2663 Collective 2664 2665 Input Parameters: 2666 + dm - The `DM` that represents the topology 2667 . viewer - The `PetscViewer` that represents the on-disk vector data 2668 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2669 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2670 - vec - The local vector to set values of 2671 2672 Level: advanced 2673 2674 Notes: 2675 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. 2676 2677 Calling sequence: 2678 .vb 2679 DMCreate(PETSC_COMM_WORLD, &dm); 2680 DMSetType(dm, DMPLEX); 2681 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2682 DMPlexTopologyLoad(dm, viewer, &sfX); 2683 DMClone(dm, §iondm); 2684 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2685 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2686 DMGetLocalVector(sectiondm, &vec); 2687 PetscObjectSetName((PetscObject)vec, "vec_name"); 2688 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2689 DMRestoreLocalVector(sectiondm, &vec); 2690 PetscSFDestroy(&lsf); 2691 PetscSFDestroy(&sfX); 2692 DMDestroy(§iondm); 2693 DMDestroy(&dm); 2694 .ve 2695 2696 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2697 `PetscSF`, `PetscViewer` 2698 @*/ 2699 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2700 { 2701 PetscBool ishdf5; 2702 2703 PetscFunctionBegin; 2704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2705 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2706 if (!sectiondm) sectiondm = dm; 2707 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2708 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2709 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2710 /* Check consistency */ 2711 { 2712 PetscSection section; 2713 PetscBool includesConstraints; 2714 PetscInt m, m1; 2715 2716 PetscCall(VecGetLocalSize(vec, &m1)); 2717 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2718 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2719 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2720 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2721 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2722 } 2723 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2724 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2725 if (ishdf5) { 2726 #if defined(PETSC_HAVE_HDF5) 2727 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2728 #else 2729 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2730 #endif 2731 } 2732 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2733 PetscFunctionReturn(PETSC_SUCCESS); 2734 } 2735 2736 PetscErrorCode DMDestroy_Plex(DM dm) 2737 { 2738 DM_Plex *mesh = (DM_Plex *)dm->data; 2739 2740 PetscFunctionBegin; 2741 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2742 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2743 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2744 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2745 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2746 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2747 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2748 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2749 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2750 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2751 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2752 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2753 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2754 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2755 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2756 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2757 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2758 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2759 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2760 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2761 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2762 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2763 PetscCall(PetscFree(mesh->cones)); 2764 PetscCall(PetscFree(mesh->coneOrientations)); 2765 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2766 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2767 PetscCall(PetscFree(mesh->supports)); 2768 PetscCall(PetscFree(mesh->cellTypes)); 2769 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2770 PetscCall(PetscFree(mesh->tetgenOpts)); 2771 PetscCall(PetscFree(mesh->triangleOpts)); 2772 PetscCall(PetscFree(mesh->transformType)); 2773 PetscCall(PetscFree(mesh->distributionName)); 2774 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2775 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2776 PetscCall(ISDestroy(&mesh->subpointIS)); 2777 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2778 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2779 if (mesh->periodic.face_sfs) { 2780 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2781 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2782 } 2783 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2784 if (mesh->periodic.periodic_points) { 2785 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2786 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2787 } 2788 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2789 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2790 PetscCall(ISDestroy(&mesh->anchorIS)); 2791 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2792 PetscCall(PetscFree(mesh->parents)); 2793 PetscCall(PetscFree(mesh->childIDs)); 2794 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2795 PetscCall(PetscFree(mesh->children)); 2796 PetscCall(DMDestroy(&mesh->referenceTree)); 2797 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2798 PetscCall(PetscFree(mesh->neighbors)); 2799 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2800 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2801 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2802 PetscCall(PetscFree(mesh)); 2803 PetscFunctionReturn(PETSC_SUCCESS); 2804 } 2805 2806 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2807 { 2808 PetscSection sectionGlobal, sectionLocal; 2809 PetscInt bs = -1, mbs; 2810 PetscInt localSize, localStart = 0; 2811 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2812 MatType mtype; 2813 ISLocalToGlobalMapping ltog; 2814 2815 PetscFunctionBegin; 2816 PetscCall(MatInitializePackage()); 2817 mtype = dm->mattype; 2818 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2819 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2820 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2821 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2822 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2823 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2824 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2825 PetscCall(MatSetType(*J, mtype)); 2826 PetscCall(MatSetFromOptions(*J)); 2827 PetscCall(MatGetBlockSize(*J, &mbs)); 2828 if (mbs > 1) bs = mbs; 2829 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2830 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2831 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2832 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2833 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2834 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2835 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2836 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2837 if (!isShell) { 2838 // There are three states with pblocks, since block starts can have no dofs: 2839 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2840 // TRUE) Block Start: The first entry in a block has been added 2841 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2842 PetscBT blst; 2843 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2844 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2845 const PetscInt *perm = NULL; 2846 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2847 PetscInt pStart, pEnd, dof, cdof, num_fields; 2848 2849 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2850 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2851 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2852 2853 PetscCall(PetscCalloc1(localSize, &pblocks)); 2854 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2855 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2856 // We need to process in the permuted order to get block sizes right 2857 for (PetscInt point = pStart; point < pEnd; ++point) { 2858 const PetscInt p = perm ? perm[point] : point; 2859 2860 switch (dm->blocking_type) { 2861 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2862 PetscInt bdof, offset; 2863 2864 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2865 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2866 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2867 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2868 if (dof > 0) { 2869 // State change 2870 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2871 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2872 2873 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2874 // Signal block concatenation 2875 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2876 } 2877 dof = dof < 0 ? -(dof + 1) : dof; 2878 bdof = cdof && (dof - cdof) ? 1 : dof; 2879 if (dof) { 2880 if (bs < 0) { 2881 bs = bdof; 2882 } else if (bs != bdof) { 2883 bs = 1; 2884 } 2885 } 2886 } break; 2887 case DM_BLOCKING_FIELD_NODE: { 2888 for (PetscInt field = 0; field < num_fields; field++) { 2889 PetscInt num_comp, bdof, offset; 2890 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2891 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2892 if (dof < 0) continue; 2893 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2894 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2895 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); 2896 PetscInt num_nodes = dof / num_comp; 2897 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2898 // Handle possibly constant block size (unlikely) 2899 bdof = cdof && (dof - cdof) ? 1 : dof; 2900 if (dof) { 2901 if (bs < 0) { 2902 bs = bdof; 2903 } else if (bs != bdof) { 2904 bs = 1; 2905 } 2906 } 2907 } 2908 } break; 2909 } 2910 } 2911 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2912 /* Must have same blocksize on all procs (some might have no points) */ 2913 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2914 bsLocal[1] = bs; 2915 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2916 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2917 else bs = bsMinMax[0]; 2918 bs = PetscMax(1, bs); 2919 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2920 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2921 PetscCall(MatSetBlockSize(*J, bs)); 2922 PetscCall(MatSetUp(*J)); 2923 } else { 2924 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2925 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2926 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2927 } 2928 if (pblocks) { // Consolidate blocks 2929 PetscInt nblocks = 0; 2930 pblocks[0] = PetscAbs(pblocks[0]); 2931 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2932 if (pblocks[i] == 0) continue; 2933 // Negative block size indicates the blocks should be concatenated 2934 if (pblocks[i] < 0) { 2935 pblocks[i] = -pblocks[i]; 2936 pblocks[nblocks - 1] += pblocks[i]; 2937 } else { 2938 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2939 } 2940 for (PetscInt j = 1; j < pblocks[i]; j++) 2941 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); 2942 } 2943 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2944 } 2945 PetscCall(PetscFree(pblocks)); 2946 } 2947 PetscCall(MatSetDM(*J, dm)); 2948 PetscFunctionReturn(PETSC_SUCCESS); 2949 } 2950 2951 /*@ 2952 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2953 2954 Not Collective 2955 2956 Input Parameter: 2957 . dm - The `DMPLEX` 2958 2959 Output Parameter: 2960 . subsection - The subdomain section 2961 2962 Level: developer 2963 2964 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2965 @*/ 2966 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2967 { 2968 DM_Plex *mesh = (DM_Plex *)dm->data; 2969 2970 PetscFunctionBegin; 2971 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2972 if (!mesh->subdomainSection) { 2973 PetscSection section; 2974 PetscSF sf; 2975 2976 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2977 PetscCall(DMGetLocalSection(dm, §ion)); 2978 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2979 PetscCall(PetscSFDestroy(&sf)); 2980 } 2981 *subsection = mesh->subdomainSection; 2982 PetscFunctionReturn(PETSC_SUCCESS); 2983 } 2984 2985 /*@ 2986 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2987 2988 Not Collective 2989 2990 Input Parameter: 2991 . dm - The `DMPLEX` 2992 2993 Output Parameters: 2994 + pStart - The first mesh point 2995 - pEnd - The upper bound for mesh points 2996 2997 Level: beginner 2998 2999 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3000 @*/ 3001 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3002 { 3003 DM_Plex *mesh = (DM_Plex *)dm->data; 3004 3005 PetscFunctionBegin; 3006 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3007 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3008 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3009 PetscFunctionReturn(PETSC_SUCCESS); 3010 } 3011 3012 /*@ 3013 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3014 3015 Not Collective 3016 3017 Input Parameters: 3018 + dm - The `DMPLEX` 3019 . pStart - The first mesh point 3020 - pEnd - The upper bound for mesh points 3021 3022 Level: beginner 3023 3024 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3025 @*/ 3026 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3027 { 3028 DM_Plex *mesh = (DM_Plex *)dm->data; 3029 3030 PetscFunctionBegin; 3031 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3032 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3033 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3034 PetscCall(PetscFree(mesh->cellTypes)); 3035 PetscFunctionReturn(PETSC_SUCCESS); 3036 } 3037 3038 /*@ 3039 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3040 3041 Not Collective 3042 3043 Input Parameters: 3044 + dm - The `DMPLEX` 3045 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3046 3047 Output Parameter: 3048 . size - The cone size for point `p` 3049 3050 Level: beginner 3051 3052 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3053 @*/ 3054 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3055 { 3056 DM_Plex *mesh = (DM_Plex *)dm->data; 3057 3058 PetscFunctionBegin; 3059 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3060 PetscAssertPointer(size, 3); 3061 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3062 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3063 PetscFunctionReturn(PETSC_SUCCESS); 3064 } 3065 3066 /*@ 3067 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3068 3069 Not Collective 3070 3071 Input Parameters: 3072 + dm - The `DMPLEX` 3073 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3074 - size - The cone size for point `p` 3075 3076 Level: beginner 3077 3078 Note: 3079 This should be called after `DMPlexSetChart()`. 3080 3081 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3082 @*/ 3083 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3084 { 3085 DM_Plex *mesh = (DM_Plex *)dm->data; 3086 3087 PetscFunctionBegin; 3088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3089 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3090 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3091 PetscFunctionReturn(PETSC_SUCCESS); 3092 } 3093 3094 /*@C 3095 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3096 3097 Not Collective 3098 3099 Input Parameters: 3100 + dm - The `DMPLEX` 3101 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3102 3103 Output Parameter: 3104 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3105 3106 Level: beginner 3107 3108 Fortran Notes: 3109 `cone` must be declared with 3110 .vb 3111 PetscInt, pointer :: cone(:) 3112 .ve 3113 3114 You must also call `DMPlexRestoreCone()` after you finish using the array. 3115 `DMPlexRestoreCone()` is not needed/available in C. 3116 3117 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3118 @*/ 3119 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3120 { 3121 DM_Plex *mesh = (DM_Plex *)dm->data; 3122 PetscInt off; 3123 3124 PetscFunctionBegin; 3125 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3126 PetscAssertPointer(cone, 3); 3127 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3128 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3129 PetscFunctionReturn(PETSC_SUCCESS); 3130 } 3131 3132 /*@ 3133 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3134 3135 Not Collective 3136 3137 Input Parameters: 3138 + dm - The `DMPLEX` 3139 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3140 3141 Output Parameters: 3142 + pConesSection - `PetscSection` describing the layout of `pCones` 3143 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3144 3145 Level: intermediate 3146 3147 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3148 @*/ 3149 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3150 { 3151 PetscSection cs, newcs; 3152 PetscInt *cones; 3153 PetscInt *newarr = NULL; 3154 PetscInt n; 3155 3156 PetscFunctionBegin; 3157 PetscCall(DMPlexGetCones(dm, &cones)); 3158 PetscCall(DMPlexGetConeSection(dm, &cs)); 3159 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3160 if (pConesSection) *pConesSection = newcs; 3161 if (pCones) { 3162 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3163 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3164 } 3165 PetscFunctionReturn(PETSC_SUCCESS); 3166 } 3167 3168 /*@ 3169 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3170 3171 Not Collective 3172 3173 Input Parameters: 3174 + dm - The `DMPLEX` 3175 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3176 3177 Output Parameter: 3178 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3179 3180 Level: advanced 3181 3182 Notes: 3183 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3184 3185 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3186 3187 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3188 `DMPlexGetDepth()`, `IS` 3189 @*/ 3190 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3191 { 3192 IS *expandedPointsAll; 3193 PetscInt depth; 3194 3195 PetscFunctionBegin; 3196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3197 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3198 PetscAssertPointer(expandedPoints, 3); 3199 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3200 *expandedPoints = expandedPointsAll[0]; 3201 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3202 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3203 PetscFunctionReturn(PETSC_SUCCESS); 3204 } 3205 3206 /*@ 3207 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3208 (DAG points of depth 0, i.e., without cones). 3209 3210 Not Collective 3211 3212 Input Parameters: 3213 + dm - The `DMPLEX` 3214 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3215 3216 Output Parameters: 3217 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3218 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3219 - sections - (optional) An array of sections which describe mappings from points to their cone points 3220 3221 Level: advanced 3222 3223 Notes: 3224 Like `DMPlexGetConeTuple()` but recursive. 3225 3226 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. 3227 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3228 3229 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\: 3230 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3231 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3232 3233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3234 `DMPlexGetDepth()`, `PetscSection`, `IS` 3235 @*/ 3236 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3237 { 3238 const PetscInt *arr0 = NULL, *cone = NULL; 3239 PetscInt *arr = NULL, *newarr = NULL; 3240 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3241 IS *expandedPoints_; 3242 PetscSection *sections_; 3243 3244 PetscFunctionBegin; 3245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3246 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3247 if (depth) PetscAssertPointer(depth, 3); 3248 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3249 if (sections) PetscAssertPointer(sections, 5); 3250 PetscCall(ISGetLocalSize(points, &n)); 3251 PetscCall(ISGetIndices(points, &arr0)); 3252 PetscCall(DMPlexGetDepth(dm, &depth_)); 3253 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3254 PetscCall(PetscCalloc1(depth_, §ions_)); 3255 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3256 for (d = depth_ - 1; d >= 0; d--) { 3257 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3258 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3259 for (i = 0; i < n; i++) { 3260 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3261 if (arr[i] >= start && arr[i] < end) { 3262 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3263 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3264 } else { 3265 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3266 } 3267 } 3268 PetscCall(PetscSectionSetUp(sections_[d])); 3269 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3270 PetscCall(PetscMalloc1(newn, &newarr)); 3271 for (i = 0; i < n; i++) { 3272 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3273 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3274 if (cn > 1) { 3275 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3276 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3277 } else { 3278 newarr[co] = arr[i]; 3279 } 3280 } 3281 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3282 arr = newarr; 3283 n = newn; 3284 } 3285 PetscCall(ISRestoreIndices(points, &arr0)); 3286 *depth = depth_; 3287 if (expandedPoints) *expandedPoints = expandedPoints_; 3288 else { 3289 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3290 PetscCall(PetscFree(expandedPoints_)); 3291 } 3292 if (sections) *sections = sections_; 3293 else { 3294 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3295 PetscCall(PetscFree(sections_)); 3296 } 3297 PetscFunctionReturn(PETSC_SUCCESS); 3298 } 3299 3300 /*@ 3301 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3302 3303 Not Collective 3304 3305 Input Parameters: 3306 + dm - The `DMPLEX` 3307 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3308 3309 Output Parameters: 3310 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3311 . expandedPoints - (optional) An array of recursively expanded cones 3312 - sections - (optional) An array of sections which describe mappings from points to their cone points 3313 3314 Level: advanced 3315 3316 Note: 3317 See `DMPlexGetConeRecursive()` 3318 3319 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3320 `DMPlexGetDepth()`, `IS`, `PetscSection` 3321 @*/ 3322 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3323 { 3324 PetscInt d, depth_; 3325 3326 PetscFunctionBegin; 3327 PetscCall(DMPlexGetDepth(dm, &depth_)); 3328 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3329 if (depth) *depth = 0; 3330 if (expandedPoints) { 3331 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3332 PetscCall(PetscFree(*expandedPoints)); 3333 } 3334 if (sections) { 3335 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3336 PetscCall(PetscFree(*sections)); 3337 } 3338 PetscFunctionReturn(PETSC_SUCCESS); 3339 } 3340 3341 /*@ 3342 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 3343 3344 Not Collective 3345 3346 Input Parameters: 3347 + dm - The `DMPLEX` 3348 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3349 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3350 3351 Level: beginner 3352 3353 Note: 3354 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3355 3356 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3357 @*/ 3358 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3359 { 3360 DM_Plex *mesh = (DM_Plex *)dm->data; 3361 PetscInt dof, off, c; 3362 3363 PetscFunctionBegin; 3364 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3365 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3366 if (dof) PetscAssertPointer(cone, 3); 3367 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3368 if (PetscDefined(USE_DEBUG)) { 3369 PetscInt pStart, pEnd; 3370 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3371 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); 3372 for (c = 0; c < dof; ++c) { 3373 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); 3374 mesh->cones[off + c] = cone[c]; 3375 } 3376 } else { 3377 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3378 } 3379 PetscFunctionReturn(PETSC_SUCCESS); 3380 } 3381 3382 /*@C 3383 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3384 3385 Not Collective 3386 3387 Input Parameters: 3388 + dm - The `DMPLEX` 3389 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3390 3391 Output Parameter: 3392 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3393 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3394 3395 Level: beginner 3396 3397 Note: 3398 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3399 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3400 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3401 with the identity. 3402 3403 Fortran Notes: 3404 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3405 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3406 3407 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3408 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3409 @*/ 3410 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3411 { 3412 DM_Plex *mesh = (DM_Plex *)dm->data; 3413 PetscInt off; 3414 3415 PetscFunctionBegin; 3416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3417 if (PetscDefined(USE_DEBUG)) { 3418 PetscInt dof; 3419 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3420 if (dof) PetscAssertPointer(coneOrientation, 3); 3421 } 3422 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3423 3424 *coneOrientation = &mesh->coneOrientations[off]; 3425 PetscFunctionReturn(PETSC_SUCCESS); 3426 } 3427 3428 /*@ 3429 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3430 3431 Not Collective 3432 3433 Input Parameters: 3434 + dm - The `DMPLEX` 3435 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3436 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3437 3438 Level: beginner 3439 3440 Notes: 3441 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3442 3443 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3444 3445 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3446 @*/ 3447 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3448 { 3449 DM_Plex *mesh = (DM_Plex *)dm->data; 3450 PetscInt pStart, pEnd; 3451 PetscInt dof, off, c; 3452 3453 PetscFunctionBegin; 3454 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3455 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3456 if (dof) PetscAssertPointer(coneOrientation, 3); 3457 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3458 if (PetscDefined(USE_DEBUG)) { 3459 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3460 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); 3461 for (c = 0; c < dof; ++c) { 3462 PetscInt cdof, o = coneOrientation[c]; 3463 3464 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3465 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); 3466 mesh->coneOrientations[off + c] = o; 3467 } 3468 } else { 3469 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3470 } 3471 PetscFunctionReturn(PETSC_SUCCESS); 3472 } 3473 3474 /*@ 3475 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3476 3477 Not Collective 3478 3479 Input Parameters: 3480 + dm - The `DMPLEX` 3481 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3482 . conePos - The local index in the cone where the point should be put 3483 - conePoint - The mesh point to insert 3484 3485 Level: beginner 3486 3487 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3488 @*/ 3489 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3490 { 3491 DM_Plex *mesh = (DM_Plex *)dm->data; 3492 PetscInt pStart, pEnd; 3493 PetscInt dof, off; 3494 3495 PetscFunctionBegin; 3496 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3497 if (PetscDefined(USE_DEBUG)) { 3498 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3499 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); 3500 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); 3501 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3502 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); 3503 } 3504 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3505 mesh->cones[off + conePos] = conePoint; 3506 PetscFunctionReturn(PETSC_SUCCESS); 3507 } 3508 3509 /*@ 3510 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3511 3512 Not Collective 3513 3514 Input Parameters: 3515 + dm - The `DMPLEX` 3516 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3517 . conePos - The local index in the cone where the point should be put 3518 - coneOrientation - The point orientation to insert 3519 3520 Level: beginner 3521 3522 Note: 3523 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3524 3525 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3526 @*/ 3527 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3528 { 3529 DM_Plex *mesh = (DM_Plex *)dm->data; 3530 PetscInt pStart, pEnd; 3531 PetscInt dof, off; 3532 3533 PetscFunctionBegin; 3534 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3535 if (PetscDefined(USE_DEBUG)) { 3536 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3537 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); 3538 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3539 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); 3540 } 3541 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3542 mesh->coneOrientations[off + conePos] = coneOrientation; 3543 PetscFunctionReturn(PETSC_SUCCESS); 3544 } 3545 3546 /*@C 3547 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3548 3549 Not collective 3550 3551 Input Parameters: 3552 + dm - The DMPlex 3553 - p - The point, which must lie in the chart set with DMPlexSetChart() 3554 3555 Output Parameters: 3556 + cone - An array of points which are on the in-edges for point `p` 3557 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3558 integer giving the prescription for cone traversal. 3559 3560 Level: beginner 3561 3562 Notes: 3563 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3564 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3565 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3566 with the identity. 3567 3568 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3569 3570 Fortran Notes: 3571 `cone` and `ornt` must be declared with 3572 .vb 3573 PetscInt, pointer :: cone(:) 3574 PetscInt, pointer :: ornt(:) 3575 .ve 3576 3577 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3578 @*/ 3579 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3580 { 3581 DM_Plex *mesh = (DM_Plex *)dm->data; 3582 3583 PetscFunctionBegin; 3584 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3585 if (mesh->tr) { 3586 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3587 } else { 3588 PetscInt off; 3589 if (PetscDefined(USE_DEBUG)) { 3590 PetscInt dof; 3591 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3592 if (dof) { 3593 if (cone) PetscAssertPointer(cone, 3); 3594 if (ornt) PetscAssertPointer(ornt, 4); 3595 } 3596 } 3597 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3598 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3599 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3600 } 3601 PetscFunctionReturn(PETSC_SUCCESS); 3602 } 3603 3604 /*@C 3605 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3606 3607 Not Collective 3608 3609 Input Parameters: 3610 + dm - The DMPlex 3611 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3612 . cone - An array of points which are on the in-edges for point p 3613 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3614 integer giving the prescription for cone traversal. 3615 3616 Level: beginner 3617 3618 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3619 @*/ 3620 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3621 { 3622 DM_Plex *mesh = (DM_Plex *)dm->data; 3623 3624 PetscFunctionBegin; 3625 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3626 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3627 PetscFunctionReturn(PETSC_SUCCESS); 3628 } 3629 3630 /*@ 3631 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3632 3633 Not Collective 3634 3635 Input Parameters: 3636 + dm - The `DMPLEX` 3637 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3638 3639 Output Parameter: 3640 . size - The support size for point `p` 3641 3642 Level: beginner 3643 3644 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3645 @*/ 3646 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3647 { 3648 DM_Plex *mesh = (DM_Plex *)dm->data; 3649 3650 PetscFunctionBegin; 3651 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3652 PetscAssertPointer(size, 3); 3653 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3654 PetscFunctionReturn(PETSC_SUCCESS); 3655 } 3656 3657 /*@ 3658 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3659 3660 Not Collective 3661 3662 Input Parameters: 3663 + dm - The `DMPLEX` 3664 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3665 - size - The support size for point `p` 3666 3667 Level: beginner 3668 3669 Note: 3670 This should be called after `DMPlexSetChart()`. 3671 3672 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3673 @*/ 3674 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3675 { 3676 DM_Plex *mesh = (DM_Plex *)dm->data; 3677 3678 PetscFunctionBegin; 3679 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3680 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3681 PetscFunctionReturn(PETSC_SUCCESS); 3682 } 3683 3684 /*@C 3685 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3686 3687 Not Collective 3688 3689 Input Parameters: 3690 + dm - The `DMPLEX` 3691 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3692 3693 Output Parameter: 3694 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3695 3696 Level: beginner 3697 3698 Fortran Notes: 3699 `support` must be declared with 3700 .vb 3701 PetscInt, pointer :: support(:) 3702 .ve 3703 3704 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3705 `DMPlexRestoreSupport()` is not needed/available in C. 3706 3707 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3708 @*/ 3709 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3710 { 3711 DM_Plex *mesh = (DM_Plex *)dm->data; 3712 PetscInt off; 3713 3714 PetscFunctionBegin; 3715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3716 PetscAssertPointer(support, 3); 3717 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3718 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3719 PetscFunctionReturn(PETSC_SUCCESS); 3720 } 3721 3722 /*@ 3723 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3724 3725 Not Collective 3726 3727 Input Parameters: 3728 + dm - The `DMPLEX` 3729 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3730 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3731 3732 Level: beginner 3733 3734 Note: 3735 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3736 3737 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3738 @*/ 3739 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3740 { 3741 DM_Plex *mesh = (DM_Plex *)dm->data; 3742 PetscInt pStart, pEnd; 3743 PetscInt dof, off, c; 3744 3745 PetscFunctionBegin; 3746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3747 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3748 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3749 if (dof) PetscAssertPointer(support, 3); 3750 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3751 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); 3752 for (c = 0; c < dof; ++c) { 3753 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); 3754 mesh->supports[off + c] = support[c]; 3755 } 3756 PetscFunctionReturn(PETSC_SUCCESS); 3757 } 3758 3759 /*@ 3760 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3761 3762 Not Collective 3763 3764 Input Parameters: 3765 + dm - The `DMPLEX` 3766 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3767 . supportPos - The local index in the cone where the point should be put 3768 - supportPoint - The mesh point to insert 3769 3770 Level: beginner 3771 3772 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3773 @*/ 3774 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3775 { 3776 DM_Plex *mesh = (DM_Plex *)dm->data; 3777 PetscInt pStart, pEnd; 3778 PetscInt dof, off; 3779 3780 PetscFunctionBegin; 3781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3782 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3783 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3784 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3785 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); 3786 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); 3787 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); 3788 mesh->supports[off + supportPos] = supportPoint; 3789 PetscFunctionReturn(PETSC_SUCCESS); 3790 } 3791 3792 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3793 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3794 { 3795 switch (ct) { 3796 case DM_POLYTOPE_SEGMENT: 3797 if (o == -1) return -2; 3798 break; 3799 case DM_POLYTOPE_TRIANGLE: 3800 if (o == -3) return -1; 3801 if (o == -2) return -3; 3802 if (o == -1) return -2; 3803 break; 3804 case DM_POLYTOPE_QUADRILATERAL: 3805 if (o == -4) return -2; 3806 if (o == -3) return -1; 3807 if (o == -2) return -4; 3808 if (o == -1) return -3; 3809 break; 3810 default: 3811 return o; 3812 } 3813 return o; 3814 } 3815 3816 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3817 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3818 { 3819 switch (ct) { 3820 case DM_POLYTOPE_SEGMENT: 3821 if ((o == -2) || (o == 1)) return -1; 3822 if (o == -1) return 0; 3823 break; 3824 case DM_POLYTOPE_TRIANGLE: 3825 if (o == -3) return -2; 3826 if (o == -2) return -1; 3827 if (o == -1) return -3; 3828 break; 3829 case DM_POLYTOPE_QUADRILATERAL: 3830 if (o == -4) return -2; 3831 if (o == -3) return -1; 3832 if (o == -2) return -4; 3833 if (o == -1) return -3; 3834 break; 3835 default: 3836 return o; 3837 } 3838 return o; 3839 } 3840 3841 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3842 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3843 { 3844 PetscInt pStart, pEnd, p; 3845 3846 PetscFunctionBegin; 3847 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3848 for (p = pStart; p < pEnd; ++p) { 3849 const PetscInt *cone, *ornt; 3850 PetscInt coneSize, c; 3851 3852 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3853 PetscCall(DMPlexGetCone(dm, p, &cone)); 3854 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3855 for (c = 0; c < coneSize; ++c) { 3856 DMPolytopeType ct; 3857 const PetscInt o = ornt[c]; 3858 3859 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3860 switch (ct) { 3861 case DM_POLYTOPE_SEGMENT: 3862 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3863 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3864 break; 3865 case DM_POLYTOPE_TRIANGLE: 3866 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3867 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3868 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3869 break; 3870 case DM_POLYTOPE_QUADRILATERAL: 3871 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3872 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3873 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3874 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3875 break; 3876 default: 3877 break; 3878 } 3879 } 3880 } 3881 PetscFunctionReturn(PETSC_SUCCESS); 3882 } 3883 3884 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3885 { 3886 DM_Plex *mesh = (DM_Plex *)dm->data; 3887 3888 PetscFunctionBeginHot; 3889 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3890 if (useCone) { 3891 PetscCall(DMPlexGetConeSize(dm, p, size)); 3892 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3893 } else { 3894 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3895 PetscCall(DMPlexGetSupport(dm, p, arr)); 3896 } 3897 } else { 3898 if (useCone) { 3899 const PetscSection s = mesh->coneSection; 3900 const PetscInt ps = p - s->pStart; 3901 const PetscInt off = s->atlasOff[ps]; 3902 3903 *size = s->atlasDof[ps]; 3904 *arr = mesh->cones + off; 3905 *ornt = mesh->coneOrientations + off; 3906 } else { 3907 const PetscSection s = mesh->supportSection; 3908 const PetscInt ps = p - s->pStart; 3909 const PetscInt off = s->atlasOff[ps]; 3910 3911 *size = s->atlasDof[ps]; 3912 *arr = mesh->supports + off; 3913 } 3914 } 3915 PetscFunctionReturn(PETSC_SUCCESS); 3916 } 3917 3918 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3919 { 3920 DM_Plex *mesh = (DM_Plex *)dm->data; 3921 3922 PetscFunctionBeginHot; 3923 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3924 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3925 } 3926 PetscFunctionReturn(PETSC_SUCCESS); 3927 } 3928 3929 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3930 { 3931 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3932 PetscInt *closure; 3933 const PetscInt *tmp = NULL, *tmpO = NULL; 3934 PetscInt off = 0, tmpSize, t; 3935 3936 PetscFunctionBeginHot; 3937 if (ornt) { 3938 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3939 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; 3940 } 3941 if (*points) { 3942 closure = *points; 3943 } else { 3944 PetscInt maxConeSize, maxSupportSize; 3945 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3946 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3947 } 3948 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3949 if (ct == DM_POLYTOPE_UNKNOWN) { 3950 closure[off++] = p; 3951 closure[off++] = 0; 3952 for (t = 0; t < tmpSize; ++t) { 3953 closure[off++] = tmp[t]; 3954 closure[off++] = tmpO ? tmpO[t] : 0; 3955 } 3956 } else { 3957 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3958 3959 /* We assume that cells with a valid type have faces with a valid type */ 3960 closure[off++] = p; 3961 closure[off++] = ornt; 3962 for (t = 0; t < tmpSize; ++t) { 3963 DMPolytopeType ft; 3964 3965 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3966 closure[off++] = tmp[arr[t]]; 3967 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3968 } 3969 } 3970 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3971 if (numPoints) *numPoints = tmpSize + 1; 3972 if (points) *points = closure; 3973 PetscFunctionReturn(PETSC_SUCCESS); 3974 } 3975 3976 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3977 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3978 { 3979 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3980 const PetscInt *cone, *ornt; 3981 PetscInt *pts, *closure = NULL; 3982 DMPolytopeType ft; 3983 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3984 PetscInt dim, coneSize, c, d, clSize, cl; 3985 3986 PetscFunctionBeginHot; 3987 PetscCall(DMGetDimension(dm, &dim)); 3988 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3989 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3990 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3991 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3992 maxSize = PetscMax(coneSeries, supportSeries); 3993 if (*points) { 3994 pts = *points; 3995 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3996 c = 0; 3997 pts[c++] = point; 3998 pts[c++] = o; 3999 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4000 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4001 for (cl = 0; cl < clSize * 2; cl += 2) { 4002 pts[c++] = closure[cl]; 4003 pts[c++] = closure[cl + 1]; 4004 } 4005 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4006 for (cl = 0; cl < clSize * 2; cl += 2) { 4007 pts[c++] = closure[cl]; 4008 pts[c++] = closure[cl + 1]; 4009 } 4010 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4011 for (d = 2; d < coneSize; ++d) { 4012 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4013 pts[c++] = cone[arr[d * 2 + 0]]; 4014 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4015 } 4016 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4017 if (dim >= 3) { 4018 for (d = 2; d < coneSize; ++d) { 4019 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4020 const PetscInt *fcone, *fornt; 4021 PetscInt fconeSize, fc, i; 4022 4023 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4024 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4025 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4026 for (fc = 0; fc < fconeSize; ++fc) { 4027 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4028 const PetscInt co = farr[fc * 2 + 1]; 4029 4030 for (i = 0; i < c; i += 2) 4031 if (pts[i] == cp) break; 4032 if (i == c) { 4033 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4034 pts[c++] = cp; 4035 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4036 } 4037 } 4038 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4039 } 4040 } 4041 *numPoints = c / 2; 4042 *points = pts; 4043 PetscFunctionReturn(PETSC_SUCCESS); 4044 } 4045 4046 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4047 { 4048 DMPolytopeType ct; 4049 PetscInt *closure, *fifo; 4050 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4051 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4052 PetscInt depth, maxSize; 4053 4054 PetscFunctionBeginHot; 4055 PetscCall(DMPlexGetDepth(dm, &depth)); 4056 if (depth == 1) { 4057 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4058 PetscFunctionReturn(PETSC_SUCCESS); 4059 } 4060 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4061 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; 4062 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4063 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4064 PetscFunctionReturn(PETSC_SUCCESS); 4065 } 4066 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4067 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4068 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4069 maxSize = PetscMax(coneSeries, supportSeries); 4070 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4071 if (*points) { 4072 closure = *points; 4073 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4074 closure[closureSize++] = p; 4075 closure[closureSize++] = ornt; 4076 fifo[fifoSize++] = p; 4077 fifo[fifoSize++] = ornt; 4078 fifo[fifoSize++] = ct; 4079 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4080 while (fifoSize - fifoStart) { 4081 const PetscInt q = fifo[fifoStart++]; 4082 const PetscInt o = fifo[fifoStart++]; 4083 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4084 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4085 const PetscInt *tmp, *tmpO = NULL; 4086 PetscInt tmpSize, t; 4087 4088 if (PetscDefined(USE_DEBUG)) { 4089 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4090 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); 4091 } 4092 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4093 for (t = 0; t < tmpSize; ++t) { 4094 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4095 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4096 const PetscInt cp = tmp[ip]; 4097 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4098 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4099 PetscInt c; 4100 4101 /* Check for duplicate */ 4102 for (c = 0; c < closureSize; c += 2) { 4103 if (closure[c] == cp) break; 4104 } 4105 if (c == closureSize) { 4106 closure[closureSize++] = cp; 4107 closure[closureSize++] = co; 4108 fifo[fifoSize++] = cp; 4109 fifo[fifoSize++] = co; 4110 fifo[fifoSize++] = ct; 4111 } 4112 } 4113 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4114 } 4115 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4116 if (numPoints) *numPoints = closureSize / 2; 4117 if (points) *points = closure; 4118 PetscFunctionReturn(PETSC_SUCCESS); 4119 } 4120 4121 /*@C 4122 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4123 4124 Not Collective 4125 4126 Input Parameters: 4127 + dm - The `DMPLEX` 4128 . p - The mesh point 4129 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4130 4131 Input/Output Parameter: 4132 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4133 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4134 otherwise the provided array is used to hold the values 4135 4136 Output Parameter: 4137 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4138 4139 Level: beginner 4140 4141 Note: 4142 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4143 4144 Fortran Notes: 4145 `points` must be declared with 4146 .vb 4147 PetscInt, pointer :: points(:) 4148 .ve 4149 and is always allocated by the function. 4150 4151 The `numPoints` argument is not present in the Fortran binding. 4152 4153 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4154 @*/ 4155 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4156 { 4157 PetscFunctionBeginHot; 4158 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4159 if (numPoints) PetscAssertPointer(numPoints, 4); 4160 if (points) PetscAssertPointer(points, 5); 4161 if (PetscDefined(USE_DEBUG)) { 4162 PetscInt pStart, pEnd; 4163 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4164 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); 4165 } 4166 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4167 PetscFunctionReturn(PETSC_SUCCESS); 4168 } 4169 4170 /*@C 4171 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4172 4173 Not Collective 4174 4175 Input Parameters: 4176 + dm - The `DMPLEX` 4177 . p - The mesh point 4178 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4179 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4180 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4181 4182 Level: beginner 4183 4184 Note: 4185 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4186 4187 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4188 @*/ 4189 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4190 { 4191 PetscFunctionBeginHot; 4192 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4193 if (numPoints) *numPoints = 0; 4194 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4195 PetscFunctionReturn(PETSC_SUCCESS); 4196 } 4197 4198 /*@ 4199 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4200 4201 Not Collective 4202 4203 Input Parameter: 4204 . dm - The `DMPLEX` 4205 4206 Output Parameters: 4207 + maxConeSize - The maximum number of in-edges 4208 - maxSupportSize - The maximum number of out-edges 4209 4210 Level: beginner 4211 4212 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4213 @*/ 4214 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4215 { 4216 DM_Plex *mesh = (DM_Plex *)dm->data; 4217 4218 PetscFunctionBegin; 4219 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4220 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4221 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4222 PetscFunctionReturn(PETSC_SUCCESS); 4223 } 4224 4225 PetscErrorCode DMSetUp_Plex(DM dm) 4226 { 4227 DM_Plex *mesh = (DM_Plex *)dm->data; 4228 PetscInt size, maxSupportSize; 4229 4230 PetscFunctionBegin; 4231 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4232 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4233 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4234 PetscCall(PetscMalloc1(size, &mesh->cones)); 4235 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4236 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4237 if (maxSupportSize) { 4238 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4239 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4240 PetscCall(PetscMalloc1(size, &mesh->supports)); 4241 } 4242 PetscFunctionReturn(PETSC_SUCCESS); 4243 } 4244 4245 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4246 { 4247 PetscFunctionBegin; 4248 if (subdm) PetscCall(DMClone(dm, subdm)); 4249 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4250 if (subdm) (*subdm)->useNatural = dm->useNatural; 4251 if (dm->useNatural && dm->sfMigration) { 4252 PetscSF sfNatural; 4253 4254 (*subdm)->sfMigration = dm->sfMigration; 4255 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4256 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4257 (*subdm)->sfNatural = sfNatural; 4258 } 4259 PetscFunctionReturn(PETSC_SUCCESS); 4260 } 4261 4262 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4263 { 4264 PetscInt i = 0; 4265 4266 PetscFunctionBegin; 4267 PetscCall(DMClone(dms[0], superdm)); 4268 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4269 (*superdm)->useNatural = PETSC_FALSE; 4270 for (i = 0; i < len; i++) { 4271 if (dms[i]->useNatural && dms[i]->sfMigration) { 4272 PetscSF sfNatural; 4273 4274 (*superdm)->sfMigration = dms[i]->sfMigration; 4275 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4276 (*superdm)->useNatural = PETSC_TRUE; 4277 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4278 (*superdm)->sfNatural = sfNatural; 4279 break; 4280 } 4281 } 4282 PetscFunctionReturn(PETSC_SUCCESS); 4283 } 4284 4285 /*@ 4286 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4287 4288 Not Collective 4289 4290 Input Parameter: 4291 . dm - The `DMPLEX` 4292 4293 Level: beginner 4294 4295 Note: 4296 This should be called after all calls to `DMPlexSetCone()` 4297 4298 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4299 @*/ 4300 PetscErrorCode DMPlexSymmetrize(DM dm) 4301 { 4302 DM_Plex *mesh = (DM_Plex *)dm->data; 4303 PetscInt *offsets; 4304 PetscInt supportSize; 4305 PetscInt pStart, pEnd, p; 4306 4307 PetscFunctionBegin; 4308 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4309 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4310 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4311 /* Calculate support sizes */ 4312 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4313 for (p = pStart; p < pEnd; ++p) { 4314 PetscInt dof, off, c; 4315 4316 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4317 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4318 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4319 } 4320 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4321 /* Calculate supports */ 4322 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4323 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4324 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4325 for (p = pStart; p < pEnd; ++p) { 4326 PetscInt dof, off, c; 4327 4328 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4329 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4330 for (c = off; c < off + dof; ++c) { 4331 const PetscInt q = mesh->cones[c]; 4332 PetscInt offS; 4333 4334 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4335 4336 mesh->supports[offS + offsets[q]] = p; 4337 ++offsets[q]; 4338 } 4339 } 4340 PetscCall(PetscFree(offsets)); 4341 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4342 PetscFunctionReturn(PETSC_SUCCESS); 4343 } 4344 4345 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4346 { 4347 IS stratumIS; 4348 4349 PetscFunctionBegin; 4350 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4351 if (PetscDefined(USE_DEBUG)) { 4352 PetscInt qStart, qEnd, numLevels, level; 4353 PetscBool overlap = PETSC_FALSE; 4354 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4355 for (level = 0; level < numLevels; level++) { 4356 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4357 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4358 overlap = PETSC_TRUE; 4359 break; 4360 } 4361 } 4362 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); 4363 } 4364 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4365 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4366 PetscCall(ISDestroy(&stratumIS)); 4367 PetscFunctionReturn(PETSC_SUCCESS); 4368 } 4369 4370 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4371 { 4372 PetscInt *pMin, *pMax; 4373 PetscInt pStart, pEnd; 4374 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4375 4376 PetscFunctionBegin; 4377 { 4378 DMLabel label2; 4379 4380 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4381 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4382 } 4383 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4384 for (PetscInt p = pStart; p < pEnd; ++p) { 4385 DMPolytopeType ct; 4386 4387 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4388 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4389 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4390 } 4391 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4392 for (PetscInt d = dmin; d <= dmax; ++d) { 4393 pMin[d] = PETSC_MAX_INT; 4394 pMax[d] = PETSC_MIN_INT; 4395 } 4396 for (PetscInt p = pStart; p < pEnd; ++p) { 4397 DMPolytopeType ct; 4398 PetscInt d; 4399 4400 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4401 d = DMPolytopeTypeGetDim(ct); 4402 pMin[d] = PetscMin(p, pMin[d]); 4403 pMax[d] = PetscMax(p, pMax[d]); 4404 } 4405 for (PetscInt d = dmin; d <= dmax; ++d) { 4406 if (pMin[d] > pMax[d]) continue; 4407 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4408 } 4409 PetscCall(PetscFree2(pMin, pMax)); 4410 PetscFunctionReturn(PETSC_SUCCESS); 4411 } 4412 4413 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4414 { 4415 PetscInt pStart, pEnd; 4416 PetscInt numRoots = 0, numLeaves = 0; 4417 4418 PetscFunctionBegin; 4419 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4420 { 4421 /* Initialize roots and count leaves */ 4422 PetscInt sMin = PETSC_MAX_INT; 4423 PetscInt sMax = PETSC_MIN_INT; 4424 PetscInt coneSize, supportSize; 4425 4426 for (PetscInt p = pStart; p < pEnd; ++p) { 4427 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4428 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4429 if (!coneSize && supportSize) { 4430 sMin = PetscMin(p, sMin); 4431 sMax = PetscMax(p, sMax); 4432 ++numRoots; 4433 } else if (!supportSize && coneSize) { 4434 ++numLeaves; 4435 } else if (!supportSize && !coneSize) { 4436 /* Isolated points */ 4437 sMin = PetscMin(p, sMin); 4438 sMax = PetscMax(p, sMax); 4439 } 4440 } 4441 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4442 } 4443 4444 if (numRoots + numLeaves == (pEnd - pStart)) { 4445 PetscInt sMin = PETSC_MAX_INT; 4446 PetscInt sMax = PETSC_MIN_INT; 4447 PetscInt coneSize, supportSize; 4448 4449 for (PetscInt p = pStart; p < pEnd; ++p) { 4450 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4451 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4452 if (!supportSize && coneSize) { 4453 sMin = PetscMin(p, sMin); 4454 sMax = PetscMax(p, sMax); 4455 } 4456 } 4457 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4458 } else { 4459 PetscInt level = 0; 4460 PetscInt qStart, qEnd; 4461 4462 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4463 while (qEnd > qStart) { 4464 PetscInt sMin = PETSC_MAX_INT; 4465 PetscInt sMax = PETSC_MIN_INT; 4466 4467 for (PetscInt q = qStart; q < qEnd; ++q) { 4468 const PetscInt *support; 4469 PetscInt supportSize; 4470 4471 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4472 PetscCall(DMPlexGetSupport(dm, q, &support)); 4473 for (PetscInt s = 0; s < supportSize; ++s) { 4474 sMin = PetscMin(support[s], sMin); 4475 sMax = PetscMax(support[s], sMax); 4476 } 4477 } 4478 PetscCall(DMLabelGetNumValues(label, &level)); 4479 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4480 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4481 } 4482 } 4483 PetscFunctionReturn(PETSC_SUCCESS); 4484 } 4485 4486 /*@ 4487 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4488 4489 Collective 4490 4491 Input Parameter: 4492 . dm - The `DMPLEX` 4493 4494 Level: beginner 4495 4496 Notes: 4497 The strata group all points of the same grade, and this function calculates the strata. This 4498 grade can be seen as the height (or depth) of the point in the DAG. 4499 4500 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4501 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4502 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4503 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4504 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4505 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4506 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4507 4508 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4509 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4510 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 4511 to interpolate only that one (e0), so that 4512 .vb 4513 cone(c0) = {e0, v2} 4514 cone(e0) = {v0, v1} 4515 .ve 4516 If `DMPlexStratify()` is run on this mesh, it will give depths 4517 .vb 4518 depth 0 = {v0, v1, v2} 4519 depth 1 = {e0, c0} 4520 .ve 4521 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4522 4523 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4524 4525 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4526 @*/ 4527 PetscErrorCode DMPlexStratify(DM dm) 4528 { 4529 DM_Plex *mesh = (DM_Plex *)dm->data; 4530 DMLabel label; 4531 PetscBool flg = PETSC_FALSE; 4532 4533 PetscFunctionBegin; 4534 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4535 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4536 4537 // Create depth label 4538 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4539 PetscCall(DMCreateLabel(dm, "depth")); 4540 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4541 4542 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4543 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4544 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4545 4546 { /* just in case there is an empty process */ 4547 PetscInt numValues, maxValues = 0, v; 4548 4549 PetscCall(DMLabelGetNumValues(label, &numValues)); 4550 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4551 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4552 } 4553 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4554 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4555 PetscFunctionReturn(PETSC_SUCCESS); 4556 } 4557 4558 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4559 { 4560 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4561 PetscInt dim, depth, pheight, coneSize; 4562 4563 PetscFunctionBeginHot; 4564 PetscCall(DMGetDimension(dm, &dim)); 4565 PetscCall(DMPlexGetDepth(dm, &depth)); 4566 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4567 pheight = depth - pdepth; 4568 if (depth <= 1) { 4569 switch (pdepth) { 4570 case 0: 4571 ct = DM_POLYTOPE_POINT; 4572 break; 4573 case 1: 4574 switch (coneSize) { 4575 case 2: 4576 ct = DM_POLYTOPE_SEGMENT; 4577 break; 4578 case 3: 4579 ct = DM_POLYTOPE_TRIANGLE; 4580 break; 4581 case 4: 4582 switch (dim) { 4583 case 2: 4584 ct = DM_POLYTOPE_QUADRILATERAL; 4585 break; 4586 case 3: 4587 ct = DM_POLYTOPE_TETRAHEDRON; 4588 break; 4589 default: 4590 break; 4591 } 4592 break; 4593 case 5: 4594 ct = DM_POLYTOPE_PYRAMID; 4595 break; 4596 case 6: 4597 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4598 break; 4599 case 8: 4600 ct = DM_POLYTOPE_HEXAHEDRON; 4601 break; 4602 default: 4603 break; 4604 } 4605 } 4606 } else { 4607 if (pdepth == 0) { 4608 ct = DM_POLYTOPE_POINT; 4609 } else if (pheight == 0) { 4610 switch (dim) { 4611 case 1: 4612 switch (coneSize) { 4613 case 2: 4614 ct = DM_POLYTOPE_SEGMENT; 4615 break; 4616 default: 4617 break; 4618 } 4619 break; 4620 case 2: 4621 switch (coneSize) { 4622 case 3: 4623 ct = DM_POLYTOPE_TRIANGLE; 4624 break; 4625 case 4: 4626 ct = DM_POLYTOPE_QUADRILATERAL; 4627 break; 4628 default: 4629 break; 4630 } 4631 break; 4632 case 3: 4633 switch (coneSize) { 4634 case 4: 4635 ct = DM_POLYTOPE_TETRAHEDRON; 4636 break; 4637 case 5: { 4638 const PetscInt *cone; 4639 PetscInt faceConeSize; 4640 4641 PetscCall(DMPlexGetCone(dm, p, &cone)); 4642 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4643 switch (faceConeSize) { 4644 case 3: 4645 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4646 break; 4647 case 4: 4648 ct = DM_POLYTOPE_PYRAMID; 4649 break; 4650 } 4651 } break; 4652 case 6: 4653 ct = DM_POLYTOPE_HEXAHEDRON; 4654 break; 4655 default: 4656 break; 4657 } 4658 break; 4659 default: 4660 break; 4661 } 4662 } else if (pheight > 0) { 4663 switch (coneSize) { 4664 case 2: 4665 ct = DM_POLYTOPE_SEGMENT; 4666 break; 4667 case 3: 4668 ct = DM_POLYTOPE_TRIANGLE; 4669 break; 4670 case 4: 4671 ct = DM_POLYTOPE_QUADRILATERAL; 4672 break; 4673 default: 4674 break; 4675 } 4676 } 4677 } 4678 *pt = ct; 4679 PetscFunctionReturn(PETSC_SUCCESS); 4680 } 4681 4682 /*@ 4683 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4684 4685 Collective 4686 4687 Input Parameter: 4688 . dm - The `DMPLEX` 4689 4690 Level: developer 4691 4692 Note: 4693 This function is normally called automatically when a cell type is requested. It creates an 4694 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4695 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4696 4697 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4698 4699 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4700 @*/ 4701 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4702 { 4703 DM_Plex *mesh; 4704 DMLabel ctLabel; 4705 PetscInt pStart, pEnd, p; 4706 4707 PetscFunctionBegin; 4708 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4709 mesh = (DM_Plex *)dm->data; 4710 PetscCall(DMCreateLabel(dm, "celltype")); 4711 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4712 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4713 PetscCall(PetscFree(mesh->cellTypes)); 4714 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4715 for (p = pStart; p < pEnd; ++p) { 4716 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4717 PetscInt pdepth; 4718 4719 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4720 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4721 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]); 4722 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4723 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4724 } 4725 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4726 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4727 PetscFunctionReturn(PETSC_SUCCESS); 4728 } 4729 4730 /*@C 4731 DMPlexGetJoin - Get an array for the join of the set of points 4732 4733 Not Collective 4734 4735 Input Parameters: 4736 + dm - The `DMPLEX` object 4737 . numPoints - The number of input points for the join 4738 - points - The input points 4739 4740 Output Parameters: 4741 + numCoveredPoints - The number of points in the join 4742 - coveredPoints - The points in the join 4743 4744 Level: intermediate 4745 4746 Note: 4747 Currently, this is restricted to a single level join 4748 4749 Fortran Notes: 4750 `converedPoints` must be declared with 4751 .vb 4752 PetscInt, pointer :: coveredPints(:) 4753 .ve 4754 4755 The `numCoveredPoints` argument is not present in the Fortran binding. 4756 4757 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4758 @*/ 4759 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4760 { 4761 DM_Plex *mesh = (DM_Plex *)dm->data; 4762 PetscInt *join[2]; 4763 PetscInt joinSize, i = 0; 4764 PetscInt dof, off, p, c, m; 4765 PetscInt maxSupportSize; 4766 4767 PetscFunctionBegin; 4768 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4769 PetscAssertPointer(points, 3); 4770 PetscAssertPointer(numCoveredPoints, 4); 4771 PetscAssertPointer(coveredPoints, 5); 4772 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4773 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4774 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4775 /* Copy in support of first point */ 4776 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4777 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4778 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4779 /* Check each successive support */ 4780 for (p = 1; p < numPoints; ++p) { 4781 PetscInt newJoinSize = 0; 4782 4783 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4784 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4785 for (c = 0; c < dof; ++c) { 4786 const PetscInt point = mesh->supports[off + c]; 4787 4788 for (m = 0; m < joinSize; ++m) { 4789 if (point == join[i][m]) { 4790 join[1 - i][newJoinSize++] = point; 4791 break; 4792 } 4793 } 4794 } 4795 joinSize = newJoinSize; 4796 i = 1 - i; 4797 } 4798 *numCoveredPoints = joinSize; 4799 *coveredPoints = join[i]; 4800 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4801 PetscFunctionReturn(PETSC_SUCCESS); 4802 } 4803 4804 /*@C 4805 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4806 4807 Not Collective 4808 4809 Input Parameters: 4810 + dm - The `DMPLEX` object 4811 . numPoints - The number of input points for the join 4812 - points - The input points 4813 4814 Output Parameters: 4815 + numCoveredPoints - The number of points in the join 4816 - coveredPoints - The points in the join 4817 4818 Level: intermediate 4819 4820 Fortran Notes: 4821 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4822 4823 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4824 @*/ 4825 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4826 { 4827 PetscFunctionBegin; 4828 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4829 if (points) PetscAssertPointer(points, 3); 4830 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4831 PetscAssertPointer(coveredPoints, 5); 4832 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4833 if (numCoveredPoints) *numCoveredPoints = 0; 4834 PetscFunctionReturn(PETSC_SUCCESS); 4835 } 4836 4837 /*@C 4838 DMPlexGetFullJoin - Get an array for the join of the set of points 4839 4840 Not Collective 4841 4842 Input Parameters: 4843 + dm - The `DMPLEX` object 4844 . numPoints - The number of input points for the join 4845 - points - The input points, its length is `numPoints` 4846 4847 Output Parameters: 4848 + numCoveredPoints - The number of points in the join 4849 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4850 4851 Level: intermediate 4852 4853 Fortran Notes: 4854 `points` and `converedPoints` must be declared with 4855 .vb 4856 PetscInt, pointer :: points(:) 4857 PetscInt, pointer :: coveredPints(:) 4858 .ve 4859 4860 The `numCoveredPoints` argument is not present in the Fortran binding. 4861 4862 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4863 @*/ 4864 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4865 { 4866 PetscInt *offsets, **closures; 4867 PetscInt *join[2]; 4868 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4869 PetscInt p, d, c, m, ms; 4870 4871 PetscFunctionBegin; 4872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4873 PetscAssertPointer(points, 3); 4874 PetscAssertPointer(numCoveredPoints, 4); 4875 PetscAssertPointer(coveredPoints, 5); 4876 4877 PetscCall(DMPlexGetDepth(dm, &depth)); 4878 PetscCall(PetscCalloc1(numPoints, &closures)); 4879 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4880 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4881 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4882 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4883 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4884 4885 for (p = 0; p < numPoints; ++p) { 4886 PetscInt closureSize; 4887 4888 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4889 4890 offsets[p * (depth + 2) + 0] = 0; 4891 for (d = 0; d < depth + 1; ++d) { 4892 PetscInt pStart, pEnd, i; 4893 4894 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4895 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4896 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4897 offsets[p * (depth + 2) + d + 1] = i; 4898 break; 4899 } 4900 } 4901 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4902 } 4903 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); 4904 } 4905 for (d = 0; d < depth + 1; ++d) { 4906 PetscInt dof; 4907 4908 /* Copy in support of first point */ 4909 dof = offsets[d + 1] - offsets[d]; 4910 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4911 /* Check each successive cone */ 4912 for (p = 1; p < numPoints && joinSize; ++p) { 4913 PetscInt newJoinSize = 0; 4914 4915 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4916 for (c = 0; c < dof; ++c) { 4917 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4918 4919 for (m = 0; m < joinSize; ++m) { 4920 if (point == join[i][m]) { 4921 join[1 - i][newJoinSize++] = point; 4922 break; 4923 } 4924 } 4925 } 4926 joinSize = newJoinSize; 4927 i = 1 - i; 4928 } 4929 if (joinSize) break; 4930 } 4931 *numCoveredPoints = joinSize; 4932 *coveredPoints = join[i]; 4933 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4934 PetscCall(PetscFree(closures)); 4935 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4936 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4937 PetscFunctionReturn(PETSC_SUCCESS); 4938 } 4939 4940 /*@C 4941 DMPlexGetMeet - Get an array for the meet of the set of points 4942 4943 Not Collective 4944 4945 Input Parameters: 4946 + dm - The `DMPLEX` object 4947 . numPoints - The number of input points for the meet 4948 - points - The input points, of length `numPoints` 4949 4950 Output Parameters: 4951 + numCoveringPoints - The number of points in the meet 4952 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4953 4954 Level: intermediate 4955 4956 Note: 4957 Currently, this is restricted to a single level meet 4958 4959 Fortran Notes: 4960 `coveringPoints` must be declared with 4961 .vb 4962 PetscInt, pointer :: coveringPoints(:) 4963 .ve 4964 4965 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4966 4967 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4968 @*/ 4969 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4970 { 4971 DM_Plex *mesh = (DM_Plex *)dm->data; 4972 PetscInt *meet[2]; 4973 PetscInt meetSize, i = 0; 4974 PetscInt dof, off, p, c, m; 4975 PetscInt maxConeSize; 4976 4977 PetscFunctionBegin; 4978 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4979 PetscAssertPointer(points, 3); 4980 PetscAssertPointer(numCoveringPoints, 4); 4981 PetscAssertPointer(coveringPoints, 5); 4982 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4983 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4984 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4985 /* Copy in cone of first point */ 4986 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4987 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4988 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4989 /* Check each successive cone */ 4990 for (p = 1; p < numPoints; ++p) { 4991 PetscInt newMeetSize = 0; 4992 4993 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4994 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4995 for (c = 0; c < dof; ++c) { 4996 const PetscInt point = mesh->cones[off + c]; 4997 4998 for (m = 0; m < meetSize; ++m) { 4999 if (point == meet[i][m]) { 5000 meet[1 - i][newMeetSize++] = point; 5001 break; 5002 } 5003 } 5004 } 5005 meetSize = newMeetSize; 5006 i = 1 - i; 5007 } 5008 *numCoveringPoints = meetSize; 5009 *coveringPoints = meet[i]; 5010 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5011 PetscFunctionReturn(PETSC_SUCCESS); 5012 } 5013 5014 /*@C 5015 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5016 5017 Not Collective 5018 5019 Input Parameters: 5020 + dm - The `DMPLEX` object 5021 . numPoints - The number of input points for the meet 5022 - points - The input points 5023 5024 Output Parameters: 5025 + numCoveredPoints - The number of points in the meet 5026 - coveredPoints - The points in the meet 5027 5028 Level: intermediate 5029 5030 Fortran Notes: 5031 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5032 5033 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5034 @*/ 5035 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5036 { 5037 PetscFunctionBegin; 5038 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5039 if (points) PetscAssertPointer(points, 3); 5040 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5041 PetscAssertPointer(coveredPoints, 5); 5042 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5043 if (numCoveredPoints) *numCoveredPoints = 0; 5044 PetscFunctionReturn(PETSC_SUCCESS); 5045 } 5046 5047 /*@C 5048 DMPlexGetFullMeet - Get an array for the meet of the set of points 5049 5050 Not Collective 5051 5052 Input Parameters: 5053 + dm - The `DMPLEX` object 5054 . numPoints - The number of input points for the meet 5055 - points - The input points, of length `numPoints` 5056 5057 Output Parameters: 5058 + numCoveredPoints - The number of points in the meet 5059 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5060 5061 Level: intermediate 5062 5063 Fortran Notes: 5064 `points` and `coveredPoints` must be declared with 5065 .vb 5066 PetscInt, pointer :: points(:) 5067 PetscInt, pointer :: coveredPoints(:) 5068 .ve 5069 5070 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5071 5072 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5073 @*/ 5074 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5075 { 5076 PetscInt *offsets, **closures; 5077 PetscInt *meet[2]; 5078 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5079 PetscInt p, h, c, m, mc; 5080 5081 PetscFunctionBegin; 5082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5083 PetscAssertPointer(points, 3); 5084 PetscAssertPointer(numCoveredPoints, 4); 5085 PetscAssertPointer(coveredPoints, 5); 5086 5087 PetscCall(DMPlexGetDepth(dm, &height)); 5088 PetscCall(PetscMalloc1(numPoints, &closures)); 5089 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5090 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5091 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5092 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5093 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5094 5095 for (p = 0; p < numPoints; ++p) { 5096 PetscInt closureSize; 5097 5098 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5099 5100 offsets[p * (height + 2) + 0] = 0; 5101 for (h = 0; h < height + 1; ++h) { 5102 PetscInt pStart, pEnd, i; 5103 5104 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5105 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5106 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5107 offsets[p * (height + 2) + h + 1] = i; 5108 break; 5109 } 5110 } 5111 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5112 } 5113 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); 5114 } 5115 for (h = 0; h < height + 1; ++h) { 5116 PetscInt dof; 5117 5118 /* Copy in cone of first point */ 5119 dof = offsets[h + 1] - offsets[h]; 5120 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5121 /* Check each successive cone */ 5122 for (p = 1; p < numPoints && meetSize; ++p) { 5123 PetscInt newMeetSize = 0; 5124 5125 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5126 for (c = 0; c < dof; ++c) { 5127 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5128 5129 for (m = 0; m < meetSize; ++m) { 5130 if (point == meet[i][m]) { 5131 meet[1 - i][newMeetSize++] = point; 5132 break; 5133 } 5134 } 5135 } 5136 meetSize = newMeetSize; 5137 i = 1 - i; 5138 } 5139 if (meetSize) break; 5140 } 5141 *numCoveredPoints = meetSize; 5142 *coveredPoints = meet[i]; 5143 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5144 PetscCall(PetscFree(closures)); 5145 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5146 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5147 PetscFunctionReturn(PETSC_SUCCESS); 5148 } 5149 5150 /*@ 5151 DMPlexEqual - Determine if two `DM` have the same topology 5152 5153 Not Collective 5154 5155 Input Parameters: 5156 + dmA - A `DMPLEX` object 5157 - dmB - A `DMPLEX` object 5158 5159 Output Parameter: 5160 . equal - `PETSC_TRUE` if the topologies are identical 5161 5162 Level: intermediate 5163 5164 Note: 5165 We are not solving graph isomorphism, so we do not permute. 5166 5167 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5168 @*/ 5169 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5170 { 5171 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5172 5173 PetscFunctionBegin; 5174 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5175 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5176 PetscAssertPointer(equal, 3); 5177 5178 *equal = PETSC_FALSE; 5179 PetscCall(DMPlexGetDepth(dmA, &depth)); 5180 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5181 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5182 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5183 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5184 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5185 for (p = pStart; p < pEnd; ++p) { 5186 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5187 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5188 5189 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5190 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5191 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5192 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5193 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5194 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5195 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5196 for (c = 0; c < coneSize; ++c) { 5197 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5198 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5199 } 5200 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5201 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5202 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5203 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5204 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5205 for (s = 0; s < supportSize; ++s) { 5206 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5207 } 5208 } 5209 *equal = PETSC_TRUE; 5210 PetscFunctionReturn(PETSC_SUCCESS); 5211 } 5212 5213 /*@ 5214 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5215 5216 Not Collective 5217 5218 Input Parameters: 5219 + dm - The `DMPLEX` 5220 . cellDim - The cell dimension 5221 - numCorners - The number of vertices on a cell 5222 5223 Output Parameter: 5224 . numFaceVertices - The number of vertices on a face 5225 5226 Level: developer 5227 5228 Note: 5229 Of course this can only work for a restricted set of symmetric shapes 5230 5231 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5232 @*/ 5233 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5234 { 5235 MPI_Comm comm; 5236 5237 PetscFunctionBegin; 5238 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5239 PetscAssertPointer(numFaceVertices, 4); 5240 switch (cellDim) { 5241 case 0: 5242 *numFaceVertices = 0; 5243 break; 5244 case 1: 5245 *numFaceVertices = 1; 5246 break; 5247 case 2: 5248 switch (numCorners) { 5249 case 3: /* triangle */ 5250 *numFaceVertices = 2; /* Edge has 2 vertices */ 5251 break; 5252 case 4: /* quadrilateral */ 5253 *numFaceVertices = 2; /* Edge has 2 vertices */ 5254 break; 5255 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5256 *numFaceVertices = 3; /* Edge has 3 vertices */ 5257 break; 5258 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5259 *numFaceVertices = 3; /* Edge has 3 vertices */ 5260 break; 5261 default: 5262 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5263 } 5264 break; 5265 case 3: 5266 switch (numCorners) { 5267 case 4: /* tetradehdron */ 5268 *numFaceVertices = 3; /* Face has 3 vertices */ 5269 break; 5270 case 6: /* tet cohesive cells */ 5271 *numFaceVertices = 4; /* Face has 4 vertices */ 5272 break; 5273 case 8: /* hexahedron */ 5274 *numFaceVertices = 4; /* Face has 4 vertices */ 5275 break; 5276 case 9: /* tet cohesive Lagrange cells */ 5277 *numFaceVertices = 6; /* Face has 6 vertices */ 5278 break; 5279 case 10: /* quadratic tetrahedron */ 5280 *numFaceVertices = 6; /* Face has 6 vertices */ 5281 break; 5282 case 12: /* hex cohesive Lagrange cells */ 5283 *numFaceVertices = 6; /* Face has 6 vertices */ 5284 break; 5285 case 18: /* quadratic tet cohesive Lagrange cells */ 5286 *numFaceVertices = 6; /* Face has 6 vertices */ 5287 break; 5288 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5289 *numFaceVertices = 9; /* Face has 9 vertices */ 5290 break; 5291 default: 5292 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5293 } 5294 break; 5295 default: 5296 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5297 } 5298 PetscFunctionReturn(PETSC_SUCCESS); 5299 } 5300 5301 /*@ 5302 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5303 5304 Not Collective 5305 5306 Input Parameter: 5307 . dm - The `DMPLEX` object 5308 5309 Output Parameter: 5310 . depthLabel - The `DMLabel` recording point depth 5311 5312 Level: developer 5313 5314 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5315 @*/ 5316 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5317 { 5318 PetscFunctionBegin; 5319 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5320 PetscAssertPointer(depthLabel, 2); 5321 *depthLabel = dm->depthLabel; 5322 PetscFunctionReturn(PETSC_SUCCESS); 5323 } 5324 5325 /*@ 5326 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5327 5328 Not Collective 5329 5330 Input Parameter: 5331 . dm - The `DMPLEX` object 5332 5333 Output Parameter: 5334 . depth - The number of strata (breadth first levels) in the DAG 5335 5336 Level: developer 5337 5338 Notes: 5339 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5340 5341 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5342 5343 An empty mesh gives -1. 5344 5345 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5346 @*/ 5347 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5348 { 5349 DM_Plex *mesh = (DM_Plex *)dm->data; 5350 DMLabel label; 5351 PetscInt d = -1; 5352 5353 PetscFunctionBegin; 5354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5355 PetscAssertPointer(depth, 2); 5356 if (mesh->tr) { 5357 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5358 } else { 5359 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5360 // Allow missing depths 5361 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5362 *depth = d; 5363 } 5364 PetscFunctionReturn(PETSC_SUCCESS); 5365 } 5366 5367 /*@ 5368 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5369 5370 Not Collective 5371 5372 Input Parameters: 5373 + dm - The `DMPLEX` object 5374 - depth - The requested depth 5375 5376 Output Parameters: 5377 + start - The first point at this `depth` 5378 - end - One beyond the last point at this `depth` 5379 5380 Level: developer 5381 5382 Notes: 5383 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5384 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5385 higher dimension, e.g., "edges". 5386 5387 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5388 @*/ 5389 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5390 { 5391 DM_Plex *mesh = (DM_Plex *)dm->data; 5392 DMLabel label; 5393 PetscInt pStart, pEnd; 5394 5395 PetscFunctionBegin; 5396 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5397 if (start) { 5398 PetscAssertPointer(start, 3); 5399 *start = 0; 5400 } 5401 if (end) { 5402 PetscAssertPointer(end, 4); 5403 *end = 0; 5404 } 5405 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5406 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5407 if (depth < 0) { 5408 if (start) *start = pStart; 5409 if (end) *end = pEnd; 5410 PetscFunctionReturn(PETSC_SUCCESS); 5411 } 5412 if (mesh->tr) { 5413 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5414 } else { 5415 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5416 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5417 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5418 } 5419 PetscFunctionReturn(PETSC_SUCCESS); 5420 } 5421 5422 /*@ 5423 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5424 5425 Not Collective 5426 5427 Input Parameters: 5428 + dm - The `DMPLEX` object 5429 - height - The requested height 5430 5431 Output Parameters: 5432 + start - The first point at this `height` 5433 - end - One beyond the last point at this `height` 5434 5435 Level: developer 5436 5437 Notes: 5438 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5439 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5440 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5441 5442 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5443 @*/ 5444 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5445 { 5446 DMLabel label; 5447 PetscInt depth, pStart, pEnd; 5448 5449 PetscFunctionBegin; 5450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5451 if (start) { 5452 PetscAssertPointer(start, 3); 5453 *start = 0; 5454 } 5455 if (end) { 5456 PetscAssertPointer(end, 4); 5457 *end = 0; 5458 } 5459 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5460 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5461 if (height < 0) { 5462 if (start) *start = pStart; 5463 if (end) *end = pEnd; 5464 PetscFunctionReturn(PETSC_SUCCESS); 5465 } 5466 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5467 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5468 else PetscCall(DMGetDimension(dm, &depth)); 5469 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5470 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5471 PetscFunctionReturn(PETSC_SUCCESS); 5472 } 5473 5474 /*@ 5475 DMPlexGetPointDepth - Get the `depth` of a given point 5476 5477 Not Collective 5478 5479 Input Parameters: 5480 + dm - The `DMPLEX` object 5481 - point - The point 5482 5483 Output Parameter: 5484 . depth - The depth of the `point` 5485 5486 Level: intermediate 5487 5488 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5489 @*/ 5490 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5491 { 5492 PetscFunctionBegin; 5493 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5494 PetscAssertPointer(depth, 3); 5495 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5496 PetscFunctionReturn(PETSC_SUCCESS); 5497 } 5498 5499 /*@ 5500 DMPlexGetPointHeight - Get the `height` of a given point 5501 5502 Not Collective 5503 5504 Input Parameters: 5505 + dm - The `DMPLEX` object 5506 - point - The point 5507 5508 Output Parameter: 5509 . height - The height of the `point` 5510 5511 Level: intermediate 5512 5513 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5514 @*/ 5515 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5516 { 5517 PetscInt n, pDepth; 5518 5519 PetscFunctionBegin; 5520 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5521 PetscAssertPointer(height, 3); 5522 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5523 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5524 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5525 PetscFunctionReturn(PETSC_SUCCESS); 5526 } 5527 5528 /*@ 5529 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5530 5531 Not Collective 5532 5533 Input Parameter: 5534 . dm - The `DMPLEX` object 5535 5536 Output Parameter: 5537 . celltypeLabel - The `DMLabel` recording cell polytope type 5538 5539 Level: developer 5540 5541 Note: 5542 This function will trigger automatica computation of cell types. This can be disabled by calling 5543 `DMCreateLabel`(dm, "celltype") beforehand. 5544 5545 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5546 @*/ 5547 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5548 { 5549 PetscFunctionBegin; 5550 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5551 PetscAssertPointer(celltypeLabel, 2); 5552 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5553 *celltypeLabel = dm->celltypeLabel; 5554 PetscFunctionReturn(PETSC_SUCCESS); 5555 } 5556 5557 /*@ 5558 DMPlexGetCellType - Get the polytope type of a given cell 5559 5560 Not Collective 5561 5562 Input Parameters: 5563 + dm - The `DMPLEX` object 5564 - cell - The cell 5565 5566 Output Parameter: 5567 . celltype - The polytope type of the cell 5568 5569 Level: intermediate 5570 5571 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5572 @*/ 5573 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5574 { 5575 DM_Plex *mesh = (DM_Plex *)dm->data; 5576 DMLabel label; 5577 PetscInt ct; 5578 5579 PetscFunctionBegin; 5580 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5581 PetscAssertPointer(celltype, 3); 5582 if (mesh->tr) { 5583 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5584 } else { 5585 PetscInt pStart, pEnd; 5586 5587 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5588 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5589 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5590 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5591 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5592 for (PetscInt p = pStart; p < pEnd; p++) { 5593 PetscCall(DMLabelGetValue(label, p, &ct)); 5594 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5595 } 5596 } 5597 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5598 if (PetscDefined(USE_DEBUG)) { 5599 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5600 PetscCall(DMLabelGetValue(label, cell, &ct)); 5601 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5602 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5603 } 5604 } 5605 PetscFunctionReturn(PETSC_SUCCESS); 5606 } 5607 5608 /*@ 5609 DMPlexSetCellType - Set the polytope type of a given cell 5610 5611 Not Collective 5612 5613 Input Parameters: 5614 + dm - The `DMPLEX` object 5615 . cell - The cell 5616 - celltype - The polytope type of the cell 5617 5618 Level: advanced 5619 5620 Note: 5621 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5622 is executed. This function will override the computed type. However, if automatic classification will not succeed 5623 and a user wants to manually specify all types, the classification must be disabled by calling 5624 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5625 5626 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5627 @*/ 5628 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5629 { 5630 DM_Plex *mesh = (DM_Plex *)dm->data; 5631 DMLabel label; 5632 PetscInt pStart, pEnd; 5633 5634 PetscFunctionBegin; 5635 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5636 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5637 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5638 PetscCall(DMLabelSetValue(label, cell, celltype)); 5639 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5640 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5641 PetscFunctionReturn(PETSC_SUCCESS); 5642 } 5643 5644 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5645 { 5646 PetscSection section; 5647 PetscInt maxHeight; 5648 const char *prefix; 5649 5650 PetscFunctionBegin; 5651 PetscCall(DMClone(dm, cdm)); 5652 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5653 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5654 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5655 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5656 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5657 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5658 PetscCall(DMSetLocalSection(*cdm, section)); 5659 PetscCall(PetscSectionDestroy(§ion)); 5660 5661 PetscCall(DMSetNumFields(*cdm, 1)); 5662 PetscCall(DMCreateDS(*cdm)); 5663 (*cdm)->cloneOpts = PETSC_TRUE; 5664 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5665 PetscFunctionReturn(PETSC_SUCCESS); 5666 } 5667 5668 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5669 { 5670 Vec coordsLocal, cellCoordsLocal; 5671 DM coordsDM, cellCoordsDM; 5672 5673 PetscFunctionBegin; 5674 *field = NULL; 5675 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5676 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5677 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5678 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5679 if (coordsLocal && coordsDM) { 5680 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5681 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5682 } 5683 PetscFunctionReturn(PETSC_SUCCESS); 5684 } 5685 5686 /*@ 5687 DMPlexGetConeSection - Return a section which describes the layout of cone data 5688 5689 Not Collective 5690 5691 Input Parameter: 5692 . dm - The `DMPLEX` object 5693 5694 Output Parameter: 5695 . section - The `PetscSection` object 5696 5697 Level: developer 5698 5699 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5700 @*/ 5701 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5702 { 5703 DM_Plex *mesh = (DM_Plex *)dm->data; 5704 5705 PetscFunctionBegin; 5706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5707 if (section) *section = mesh->coneSection; 5708 PetscFunctionReturn(PETSC_SUCCESS); 5709 } 5710 5711 /*@ 5712 DMPlexGetSupportSection - Return a section which describes the layout of support data 5713 5714 Not Collective 5715 5716 Input Parameter: 5717 . dm - The `DMPLEX` object 5718 5719 Output Parameter: 5720 . section - The `PetscSection` object 5721 5722 Level: developer 5723 5724 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5725 @*/ 5726 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5727 { 5728 DM_Plex *mesh = (DM_Plex *)dm->data; 5729 5730 PetscFunctionBegin; 5731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5732 if (section) *section = mesh->supportSection; 5733 PetscFunctionReturn(PETSC_SUCCESS); 5734 } 5735 5736 /*@C 5737 DMPlexGetCones - Return cone data 5738 5739 Not Collective 5740 5741 Input Parameter: 5742 . dm - The `DMPLEX` object 5743 5744 Output Parameter: 5745 . cones - The cone for each point 5746 5747 Level: developer 5748 5749 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5750 @*/ 5751 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5752 { 5753 DM_Plex *mesh = (DM_Plex *)dm->data; 5754 5755 PetscFunctionBegin; 5756 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5757 if (cones) *cones = mesh->cones; 5758 PetscFunctionReturn(PETSC_SUCCESS); 5759 } 5760 5761 /*@C 5762 DMPlexGetConeOrientations - Return cone orientation data 5763 5764 Not Collective 5765 5766 Input Parameter: 5767 . dm - The `DMPLEX` object 5768 5769 Output Parameter: 5770 . coneOrientations - The array of cone orientations for all points 5771 5772 Level: developer 5773 5774 Notes: 5775 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5776 as returned by `DMPlexGetConeOrientation()`. 5777 5778 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5779 5780 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5781 @*/ 5782 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5783 { 5784 DM_Plex *mesh = (DM_Plex *)dm->data; 5785 5786 PetscFunctionBegin; 5787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5788 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5789 PetscFunctionReturn(PETSC_SUCCESS); 5790 } 5791 5792 /******************************** FEM Support **********************************/ 5793 5794 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5795 { 5796 PetscInt depth; 5797 5798 PetscFunctionBegin; 5799 PetscCall(DMPlexGetDepth(plex, &depth)); 5800 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5801 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5802 PetscFunctionReturn(PETSC_SUCCESS); 5803 } 5804 5805 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5806 { 5807 PetscInt depth; 5808 5809 PetscFunctionBegin; 5810 PetscCall(DMPlexGetDepth(plex, &depth)); 5811 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5812 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5813 PetscFunctionReturn(PETSC_SUCCESS); 5814 } 5815 5816 /* 5817 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5818 representing a line in the section. 5819 */ 5820 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5821 { 5822 PetscObject obj; 5823 PetscClassId id; 5824 PetscFE fe = NULL; 5825 5826 PetscFunctionBeginHot; 5827 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5828 PetscCall(DMGetField(dm, field, NULL, &obj)); 5829 PetscCall(PetscObjectGetClassId(obj, &id)); 5830 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5831 5832 if (!fe) { 5833 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5834 /* An order k SEM disc has k-1 dofs on an edge */ 5835 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5836 *k = *k / *Nc + 1; 5837 } else { 5838 PetscInt dual_space_size, dim; 5839 PetscDualSpace dsp; 5840 5841 PetscCall(DMGetDimension(dm, &dim)); 5842 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5843 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5844 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5845 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5846 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5847 } 5848 PetscFunctionReturn(PETSC_SUCCESS); 5849 } 5850 5851 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5852 { 5853 PetscFunctionBeginHot; 5854 if (tensor) { 5855 *dof = PetscPowInt(k + 1, dim); 5856 } else { 5857 switch (dim) { 5858 case 1: 5859 *dof = k + 1; 5860 break; 5861 case 2: 5862 *dof = ((k + 1) * (k + 2)) / 2; 5863 break; 5864 case 3: 5865 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5866 break; 5867 default: 5868 *dof = 0; 5869 } 5870 } 5871 PetscFunctionReturn(PETSC_SUCCESS); 5872 } 5873 5874 /*@ 5875 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5876 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5877 section provided (or the section of the `DM`). 5878 5879 Input Parameters: 5880 + dm - The `DM` 5881 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5882 - section - The `PetscSection` to reorder, or `NULL` for the default section 5883 5884 Example: 5885 A typical interpolated single-quad mesh might order points as 5886 .vb 5887 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5888 5889 v4 -- e6 -- v3 5890 | | 5891 e7 c0 e8 5892 | | 5893 v1 -- e5 -- v2 5894 .ve 5895 5896 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5897 dofs in the order of points, e.g., 5898 .vb 5899 c0 -> [0,1,2,3] 5900 v1 -> [4] 5901 ... 5902 e5 -> [8, 9] 5903 .ve 5904 5905 which corresponds to the dofs 5906 .vb 5907 6 10 11 7 5908 13 2 3 15 5909 12 0 1 14 5910 4 8 9 5 5911 .ve 5912 5913 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5914 .vb 5915 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5916 .ve 5917 5918 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5919 .vb 5920 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5921 .ve 5922 5923 Level: developer 5924 5925 Notes: 5926 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5927 degree of the basis. 5928 5929 This is required to run with libCEED. 5930 5931 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5932 @*/ 5933 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5934 { 5935 DMLabel label; 5936 PetscInt dim, depth = -1, eStart = -1, Nf; 5937 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5938 5939 PetscFunctionBegin; 5940 PetscCall(DMGetDimension(dm, &dim)); 5941 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5942 if (point < 0) { 5943 PetscInt sStart, sEnd; 5944 5945 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5946 point = sEnd - sStart ? sStart : point; 5947 } 5948 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5949 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5950 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5951 if (depth == 1) { 5952 eStart = point; 5953 } else if (depth == dim) { 5954 const PetscInt *cone; 5955 5956 PetscCall(DMPlexGetCone(dm, point, &cone)); 5957 if (dim == 2) eStart = cone[0]; 5958 else if (dim == 3) { 5959 const PetscInt *cone2; 5960 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5961 eStart = cone2[0]; 5962 } 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); 5963 } 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); 5964 5965 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5966 for (PetscInt d = 1; d <= dim; d++) { 5967 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5968 PetscInt *perm; 5969 5970 for (f = 0; f < Nf; ++f) { 5971 PetscInt dof; 5972 5973 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5974 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5975 if (!continuous && d < dim) continue; 5976 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5977 size += dof * Nc; 5978 } 5979 PetscCall(PetscMalloc1(size, &perm)); 5980 for (f = 0; f < Nf; ++f) { 5981 switch (d) { 5982 case 1: 5983 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5984 if (!continuous && d < dim) continue; 5985 /* 5986 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5987 We want [ vtx0; edge of length k-1; vtx1 ] 5988 */ 5989 if (continuous) { 5990 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5991 for (i = 0; i < k - 1; i++) 5992 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5993 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5994 foffset = offset; 5995 } else { 5996 PetscInt dof; 5997 5998 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5999 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6000 foffset = offset; 6001 } 6002 break; 6003 case 2: 6004 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6005 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6006 if (!continuous && d < dim) continue; 6007 /* The SEM order is 6008 6009 v_lb, {e_b}, v_rb, 6010 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6011 v_lt, reverse {e_t}, v_rt 6012 */ 6013 if (continuous) { 6014 const PetscInt of = 0; 6015 const PetscInt oeb = of + PetscSqr(k - 1); 6016 const PetscInt oer = oeb + (k - 1); 6017 const PetscInt oet = oer + (k - 1); 6018 const PetscInt oel = oet + (k - 1); 6019 const PetscInt ovlb = oel + (k - 1); 6020 const PetscInt ovrb = ovlb + 1; 6021 const PetscInt ovrt = ovrb + 1; 6022 const PetscInt ovlt = ovrt + 1; 6023 PetscInt o; 6024 6025 /* bottom */ 6026 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6027 for (o = oeb; o < oer; ++o) 6028 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6029 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6030 /* middle */ 6031 for (i = 0; i < k - 1; ++i) { 6032 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6033 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6034 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6035 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6036 } 6037 /* top */ 6038 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6039 for (o = oel - 1; o >= oet; --o) 6040 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6041 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6042 foffset = offset; 6043 } else { 6044 PetscInt dof; 6045 6046 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6047 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6048 foffset = offset; 6049 } 6050 break; 6051 case 3: 6052 /* The original hex closure is 6053 6054 {c, 6055 f_b, f_t, f_f, f_b, f_r, f_l, 6056 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6057 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6058 */ 6059 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6060 if (!continuous && d < dim) continue; 6061 /* The SEM order is 6062 Bottom Slice 6063 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6064 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6065 v_blb, {e_bb}, v_brb, 6066 6067 Middle Slice (j) 6068 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6069 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6070 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6071 6072 Top Slice 6073 v_tlf, {e_tf}, v_trf, 6074 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6075 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6076 */ 6077 if (continuous) { 6078 const PetscInt oc = 0; 6079 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6080 const PetscInt oft = ofb + PetscSqr(k - 1); 6081 const PetscInt off = oft + PetscSqr(k - 1); 6082 const PetscInt ofk = off + PetscSqr(k - 1); 6083 const PetscInt ofr = ofk + PetscSqr(k - 1); 6084 const PetscInt ofl = ofr + PetscSqr(k - 1); 6085 const PetscInt oebl = ofl + PetscSqr(k - 1); 6086 const PetscInt oebb = oebl + (k - 1); 6087 const PetscInt oebr = oebb + (k - 1); 6088 const PetscInt oebf = oebr + (k - 1); 6089 const PetscInt oetf = oebf + (k - 1); 6090 const PetscInt oetr = oetf + (k - 1); 6091 const PetscInt oetb = oetr + (k - 1); 6092 const PetscInt oetl = oetb + (k - 1); 6093 const PetscInt oerf = oetl + (k - 1); 6094 const PetscInt oelf = oerf + (k - 1); 6095 const PetscInt oelb = oelf + (k - 1); 6096 const PetscInt oerb = oelb + (k - 1); 6097 const PetscInt ovblf = oerb + (k - 1); 6098 const PetscInt ovblb = ovblf + 1; 6099 const PetscInt ovbrb = ovblb + 1; 6100 const PetscInt ovbrf = ovbrb + 1; 6101 const PetscInt ovtlf = ovbrf + 1; 6102 const PetscInt ovtrf = ovtlf + 1; 6103 const PetscInt ovtrb = ovtrf + 1; 6104 const PetscInt ovtlb = ovtrb + 1; 6105 PetscInt o, n; 6106 6107 /* Bottom Slice */ 6108 /* bottom */ 6109 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6110 for (o = oetf - 1; o >= oebf; --o) 6111 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6112 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6113 /* middle */ 6114 for (i = 0; i < k - 1; ++i) { 6115 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6116 for (n = 0; n < k - 1; ++n) { 6117 o = ofb + n * (k - 1) + i; 6118 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6119 } 6120 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6121 } 6122 /* top */ 6123 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6124 for (o = oebb; o < oebr; ++o) 6125 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6126 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6127 6128 /* Middle Slice */ 6129 for (j = 0; j < k - 1; ++j) { 6130 /* bottom */ 6131 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6132 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6133 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6134 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6135 /* middle */ 6136 for (i = 0; i < k - 1; ++i) { 6137 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6138 for (n = 0; n < k - 1; ++n) 6139 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6140 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6141 } 6142 /* top */ 6143 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6144 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6145 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6146 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6147 } 6148 6149 /* Top Slice */ 6150 /* bottom */ 6151 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6152 for (o = oetf; o < oetr; ++o) 6153 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6154 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6155 /* middle */ 6156 for (i = 0; i < k - 1; ++i) { 6157 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6158 for (n = 0; n < k - 1; ++n) 6159 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6160 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6161 } 6162 /* top */ 6163 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6164 for (o = oetl - 1; o >= oetb; --o) 6165 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6166 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6167 6168 foffset = offset; 6169 } else { 6170 PetscInt dof; 6171 6172 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6173 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6174 foffset = offset; 6175 } 6176 break; 6177 default: 6178 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6179 } 6180 } 6181 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6182 /* Check permutation */ 6183 { 6184 PetscInt *check; 6185 6186 PetscCall(PetscMalloc1(size, &check)); 6187 for (i = 0; i < size; ++i) { 6188 check[i] = -1; 6189 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6190 } 6191 for (i = 0; i < size; ++i) check[perm[i]] = i; 6192 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6193 PetscCall(PetscFree(check)); 6194 } 6195 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6196 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6197 PetscInt *loc_perm; 6198 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6199 for (PetscInt i = 0; i < size; i++) { 6200 loc_perm[i] = perm[i]; 6201 loc_perm[size + i] = size + perm[i]; 6202 } 6203 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6204 } 6205 } 6206 PetscFunctionReturn(PETSC_SUCCESS); 6207 } 6208 6209 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6210 { 6211 PetscDS prob; 6212 PetscInt depth, Nf, h; 6213 DMLabel label; 6214 6215 PetscFunctionBeginHot; 6216 PetscCall(DMGetDS(dm, &prob)); 6217 Nf = prob->Nf; 6218 label = dm->depthLabel; 6219 *dspace = NULL; 6220 if (field < Nf) { 6221 PetscObject disc = prob->disc[field]; 6222 6223 if (disc->classid == PETSCFE_CLASSID) { 6224 PetscDualSpace dsp; 6225 6226 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6227 PetscCall(DMLabelGetNumValues(label, &depth)); 6228 PetscCall(DMLabelGetValue(label, point, &h)); 6229 h = depth - 1 - h; 6230 if (h) { 6231 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6232 } else { 6233 *dspace = dsp; 6234 } 6235 } 6236 } 6237 PetscFunctionReturn(PETSC_SUCCESS); 6238 } 6239 6240 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6241 { 6242 PetscScalar *array; 6243 const PetscScalar *vArray; 6244 const PetscInt *cone, *coneO; 6245 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6246 6247 PetscFunctionBeginHot; 6248 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6249 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6250 PetscCall(DMPlexGetCone(dm, point, &cone)); 6251 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6252 if (!values || !*values) { 6253 if ((point >= pStart) && (point < pEnd)) { 6254 PetscInt dof; 6255 6256 PetscCall(PetscSectionGetDof(section, point, &dof)); 6257 size += dof; 6258 } 6259 for (p = 0; p < numPoints; ++p) { 6260 const PetscInt cp = cone[p]; 6261 PetscInt dof; 6262 6263 if ((cp < pStart) || (cp >= pEnd)) continue; 6264 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6265 size += dof; 6266 } 6267 if (!values) { 6268 if (csize) *csize = size; 6269 PetscFunctionReturn(PETSC_SUCCESS); 6270 } 6271 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6272 } else { 6273 array = *values; 6274 } 6275 size = 0; 6276 PetscCall(VecGetArrayRead(v, &vArray)); 6277 if ((point >= pStart) && (point < pEnd)) { 6278 PetscInt dof, off, d; 6279 const PetscScalar *varr; 6280 6281 PetscCall(PetscSectionGetDof(section, point, &dof)); 6282 PetscCall(PetscSectionGetOffset(section, point, &off)); 6283 varr = PetscSafePointerPlusOffset(vArray, off); 6284 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6285 size += dof; 6286 } 6287 for (p = 0; p < numPoints; ++p) { 6288 const PetscInt cp = cone[p]; 6289 PetscInt o = coneO[p]; 6290 PetscInt dof, off, d; 6291 const PetscScalar *varr; 6292 6293 if ((cp < pStart) || (cp >= pEnd)) continue; 6294 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6295 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6296 varr = PetscSafePointerPlusOffset(vArray, off); 6297 if (o >= 0) { 6298 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6299 } else { 6300 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6301 } 6302 size += dof; 6303 } 6304 PetscCall(VecRestoreArrayRead(v, &vArray)); 6305 if (!*values) { 6306 if (csize) *csize = size; 6307 *values = array; 6308 } else { 6309 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6310 *csize = size; 6311 } 6312 PetscFunctionReturn(PETSC_SUCCESS); 6313 } 6314 6315 /* Compress out points not in the section */ 6316 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6317 { 6318 const PetscInt np = *numPoints; 6319 PetscInt pStart, pEnd, p, q; 6320 6321 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6322 for (p = 0, q = 0; p < np; ++p) { 6323 const PetscInt r = points[p * 2]; 6324 if ((r >= pStart) && (r < pEnd)) { 6325 points[q * 2] = r; 6326 points[q * 2 + 1] = points[p * 2 + 1]; 6327 ++q; 6328 } 6329 } 6330 *numPoints = q; 6331 return PETSC_SUCCESS; 6332 } 6333 6334 /* Compressed closure does not apply closure permutation */ 6335 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6336 { 6337 const PetscInt *cla = NULL; 6338 PetscInt np, *pts = NULL; 6339 6340 PetscFunctionBeginHot; 6341 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6342 if (!ornt && *clPoints) { 6343 PetscInt dof, off; 6344 6345 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6346 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6347 PetscCall(ISGetIndices(*clPoints, &cla)); 6348 np = dof / 2; 6349 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6350 } else { 6351 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6352 PetscCall(CompressPoints_Private(section, &np, pts)); 6353 } 6354 *numPoints = np; 6355 *points = pts; 6356 *clp = cla; 6357 PetscFunctionReturn(PETSC_SUCCESS); 6358 } 6359 6360 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6361 { 6362 PetscFunctionBeginHot; 6363 if (!*clPoints) { 6364 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6365 } else { 6366 PetscCall(ISRestoreIndices(*clPoints, clp)); 6367 } 6368 *numPoints = 0; 6369 *points = NULL; 6370 *clSec = NULL; 6371 *clPoints = NULL; 6372 *clp = NULL; 6373 PetscFunctionReturn(PETSC_SUCCESS); 6374 } 6375 6376 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6377 { 6378 PetscInt offset = 0, p; 6379 const PetscInt **perms = NULL; 6380 const PetscScalar **flips = NULL; 6381 6382 PetscFunctionBeginHot; 6383 *size = 0; 6384 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6385 for (p = 0; p < numPoints; p++) { 6386 const PetscInt point = points[2 * p]; 6387 const PetscInt *perm = perms ? perms[p] : NULL; 6388 const PetscScalar *flip = flips ? flips[p] : NULL; 6389 PetscInt dof, off, d; 6390 const PetscScalar *varr; 6391 6392 PetscCall(PetscSectionGetDof(section, point, &dof)); 6393 PetscCall(PetscSectionGetOffset(section, point, &off)); 6394 varr = PetscSafePointerPlusOffset(vArray, off); 6395 if (clperm) { 6396 if (perm) { 6397 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6398 } else { 6399 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6400 } 6401 if (flip) { 6402 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6403 } 6404 } else { 6405 if (perm) { 6406 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6407 } else { 6408 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6409 } 6410 if (flip) { 6411 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6412 } 6413 } 6414 offset += dof; 6415 } 6416 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6417 *size = offset; 6418 PetscFunctionReturn(PETSC_SUCCESS); 6419 } 6420 6421 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[]) 6422 { 6423 PetscInt offset = 0, f; 6424 6425 PetscFunctionBeginHot; 6426 *size = 0; 6427 for (f = 0; f < numFields; ++f) { 6428 PetscInt p; 6429 const PetscInt **perms = NULL; 6430 const PetscScalar **flips = NULL; 6431 6432 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6433 for (p = 0; p < numPoints; p++) { 6434 const PetscInt point = points[2 * p]; 6435 PetscInt fdof, foff, b; 6436 const PetscScalar *varr; 6437 const PetscInt *perm = perms ? perms[p] : NULL; 6438 const PetscScalar *flip = flips ? flips[p] : NULL; 6439 6440 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6441 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6442 varr = &vArray[foff]; 6443 if (clperm) { 6444 if (perm) { 6445 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6446 } else { 6447 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6448 } 6449 if (flip) { 6450 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6451 } 6452 } else { 6453 if (perm) { 6454 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6455 } else { 6456 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6457 } 6458 if (flip) { 6459 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6460 } 6461 } 6462 offset += fdof; 6463 } 6464 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6465 } 6466 *size = offset; 6467 PetscFunctionReturn(PETSC_SUCCESS); 6468 } 6469 6470 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6471 { 6472 PetscSection clSection; 6473 IS clPoints; 6474 PetscInt *points = NULL; 6475 const PetscInt *clp, *perm = NULL; 6476 PetscInt depth, numFields, numPoints, asize; 6477 6478 PetscFunctionBeginHot; 6479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6480 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6481 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6482 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6483 PetscCall(DMPlexGetDepth(dm, &depth)); 6484 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6485 if (depth == 1 && numFields < 2) { 6486 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6487 PetscFunctionReturn(PETSC_SUCCESS); 6488 } 6489 /* Get points */ 6490 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6491 /* Get sizes */ 6492 asize = 0; 6493 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6494 PetscInt dof; 6495 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6496 asize += dof; 6497 } 6498 if (values) { 6499 const PetscScalar *vArray; 6500 PetscInt size; 6501 6502 if (*values) { 6503 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); 6504 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6505 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6506 PetscCall(VecGetArrayRead(v, &vArray)); 6507 /* Get values */ 6508 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6509 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6510 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6511 /* Cleanup array */ 6512 PetscCall(VecRestoreArrayRead(v, &vArray)); 6513 } 6514 if (csize) *csize = asize; 6515 /* Cleanup points */ 6516 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6517 PetscFunctionReturn(PETSC_SUCCESS); 6518 } 6519 6520 /*@C 6521 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6522 6523 Not collective 6524 6525 Input Parameters: 6526 + dm - The `DM` 6527 . section - The section describing the layout in `v`, or `NULL` to use the default section 6528 . v - The local vector 6529 - point - The point in the `DM` 6530 6531 Input/Output Parameters: 6532 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6533 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6534 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6535 6536 Level: intermediate 6537 6538 Notes: 6539 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6540 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6541 assembly function, and a user may already have allocated storage for this operation. 6542 6543 A typical use could be 6544 .vb 6545 values = NULL; 6546 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6547 for (cl = 0; cl < clSize; ++cl) { 6548 <Compute on closure> 6549 } 6550 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6551 .ve 6552 or 6553 .vb 6554 PetscMalloc1(clMaxSize, &values); 6555 for (p = pStart; p < pEnd; ++p) { 6556 clSize = clMaxSize; 6557 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6558 for (cl = 0; cl < clSize; ++cl) { 6559 <Compute on closure> 6560 } 6561 } 6562 PetscFree(values); 6563 .ve 6564 6565 Fortran Notes: 6566 The `csize` argument is not present in the Fortran binding. 6567 6568 `values` must be declared with 6569 .vb 6570 PetscScalar,dimension(:),pointer :: values 6571 .ve 6572 and it will be allocated internally by PETSc to hold the values returned 6573 6574 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6575 @*/ 6576 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6577 { 6578 PetscFunctionBeginHot; 6579 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6580 PetscFunctionReturn(PETSC_SUCCESS); 6581 } 6582 6583 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6584 { 6585 DMLabel depthLabel; 6586 PetscSection clSection; 6587 IS clPoints; 6588 PetscScalar *array; 6589 const PetscScalar *vArray; 6590 PetscInt *points = NULL; 6591 const PetscInt *clp, *perm = NULL; 6592 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6593 6594 PetscFunctionBeginHot; 6595 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6596 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6597 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6598 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6599 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6600 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6601 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6602 if (mdepth == 1 && numFields < 2) { 6603 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6604 PetscFunctionReturn(PETSC_SUCCESS); 6605 } 6606 /* Get points */ 6607 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6608 for (clsize = 0, p = 0; p < Np; p++) { 6609 PetscInt dof; 6610 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6611 clsize += dof; 6612 } 6613 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6614 /* Filter points */ 6615 for (p = 0; p < numPoints * 2; p += 2) { 6616 PetscInt dep; 6617 6618 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6619 if (dep != depth) continue; 6620 points[Np * 2 + 0] = points[p]; 6621 points[Np * 2 + 1] = points[p + 1]; 6622 ++Np; 6623 } 6624 /* Get array */ 6625 if (!values || !*values) { 6626 PetscInt asize = 0, dof; 6627 6628 for (p = 0; p < Np * 2; p += 2) { 6629 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6630 asize += dof; 6631 } 6632 if (!values) { 6633 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6634 if (csize) *csize = asize; 6635 PetscFunctionReturn(PETSC_SUCCESS); 6636 } 6637 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6638 } else { 6639 array = *values; 6640 } 6641 PetscCall(VecGetArrayRead(v, &vArray)); 6642 /* Get values */ 6643 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6644 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6645 /* Cleanup points */ 6646 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6647 /* Cleanup array */ 6648 PetscCall(VecRestoreArrayRead(v, &vArray)); 6649 if (!*values) { 6650 if (csize) *csize = size; 6651 *values = array; 6652 } else { 6653 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6654 *csize = size; 6655 } 6656 PetscFunctionReturn(PETSC_SUCCESS); 6657 } 6658 6659 /*@C 6660 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6661 6662 Not collective 6663 6664 Input Parameters: 6665 + dm - The `DM` 6666 . section - The section describing the layout in `v`, or `NULL` to use the default section 6667 . v - The local vector 6668 . point - The point in the `DM` 6669 . csize - The number of values in the closure, or `NULL` 6670 - values - The array of values 6671 6672 Level: intermediate 6673 6674 Note: 6675 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6676 6677 Fortran Note: 6678 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6679 6680 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6681 @*/ 6682 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6683 { 6684 PetscInt size = 0; 6685 6686 PetscFunctionBegin; 6687 /* Should work without recalculating size */ 6688 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6689 *values = NULL; 6690 PetscFunctionReturn(PETSC_SUCCESS); 6691 } 6692 6693 static inline void add(PetscScalar *x, PetscScalar y) 6694 { 6695 *x += y; 6696 } 6697 static inline void insert(PetscScalar *x, PetscScalar y) 6698 { 6699 *x = y; 6700 } 6701 6702 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[]) 6703 { 6704 PetscInt cdof; /* The number of constraints on this point */ 6705 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6706 PetscScalar *a; 6707 PetscInt off, cind = 0, k; 6708 6709 PetscFunctionBegin; 6710 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6711 PetscCall(PetscSectionGetOffset(section, point, &off)); 6712 a = &array[off]; 6713 if (!cdof || setBC) { 6714 if (clperm) { 6715 if (perm) { 6716 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6717 } else { 6718 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6719 } 6720 } else { 6721 if (perm) { 6722 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6723 } else { 6724 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6725 } 6726 } 6727 } else { 6728 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6729 if (clperm) { 6730 if (perm) { 6731 for (k = 0; k < dof; ++k) { 6732 if ((cind < cdof) && (k == cdofs[cind])) { 6733 ++cind; 6734 continue; 6735 } 6736 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6737 } 6738 } else { 6739 for (k = 0; k < dof; ++k) { 6740 if ((cind < cdof) && (k == cdofs[cind])) { 6741 ++cind; 6742 continue; 6743 } 6744 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6745 } 6746 } 6747 } else { 6748 if (perm) { 6749 for (k = 0; k < dof; ++k) { 6750 if ((cind < cdof) && (k == cdofs[cind])) { 6751 ++cind; 6752 continue; 6753 } 6754 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6755 } 6756 } else { 6757 for (k = 0; k < dof; ++k) { 6758 if ((cind < cdof) && (k == cdofs[cind])) { 6759 ++cind; 6760 continue; 6761 } 6762 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6763 } 6764 } 6765 } 6766 } 6767 PetscFunctionReturn(PETSC_SUCCESS); 6768 } 6769 6770 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[]) 6771 { 6772 PetscInt cdof; /* The number of constraints on this point */ 6773 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6774 PetscScalar *a; 6775 PetscInt off, cind = 0, k; 6776 6777 PetscFunctionBegin; 6778 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6779 PetscCall(PetscSectionGetOffset(section, point, &off)); 6780 a = &array[off]; 6781 if (cdof) { 6782 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6783 if (clperm) { 6784 if (perm) { 6785 for (k = 0; k < dof; ++k) { 6786 if ((cind < cdof) && (k == cdofs[cind])) { 6787 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6788 cind++; 6789 } 6790 } 6791 } else { 6792 for (k = 0; k < dof; ++k) { 6793 if ((cind < cdof) && (k == cdofs[cind])) { 6794 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6795 cind++; 6796 } 6797 } 6798 } 6799 } else { 6800 if (perm) { 6801 for (k = 0; k < dof; ++k) { 6802 if ((cind < cdof) && (k == cdofs[cind])) { 6803 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6804 cind++; 6805 } 6806 } 6807 } else { 6808 for (k = 0; k < dof; ++k) { 6809 if ((cind < cdof) && (k == cdofs[cind])) { 6810 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6811 cind++; 6812 } 6813 } 6814 } 6815 } 6816 } 6817 PetscFunctionReturn(PETSC_SUCCESS); 6818 } 6819 6820 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[]) 6821 { 6822 PetscScalar *a; 6823 PetscInt fdof, foff, fcdof, foffset = *offset; 6824 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6825 PetscInt cind = 0, b; 6826 6827 PetscFunctionBegin; 6828 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6829 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6830 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6831 a = &array[foff]; 6832 if (!fcdof || setBC) { 6833 if (clperm) { 6834 if (perm) { 6835 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6836 } else { 6837 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6838 } 6839 } else { 6840 if (perm) { 6841 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6842 } else { 6843 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6844 } 6845 } 6846 } else { 6847 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6848 if (clperm) { 6849 if (perm) { 6850 for (b = 0; b < fdof; b++) { 6851 if ((cind < fcdof) && (b == fcdofs[cind])) { 6852 ++cind; 6853 continue; 6854 } 6855 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6856 } 6857 } else { 6858 for (b = 0; b < fdof; b++) { 6859 if ((cind < fcdof) && (b == fcdofs[cind])) { 6860 ++cind; 6861 continue; 6862 } 6863 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6864 } 6865 } 6866 } else { 6867 if (perm) { 6868 for (b = 0; b < fdof; b++) { 6869 if ((cind < fcdof) && (b == fcdofs[cind])) { 6870 ++cind; 6871 continue; 6872 } 6873 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6874 } 6875 } else { 6876 for (b = 0; b < fdof; b++) { 6877 if ((cind < fcdof) && (b == fcdofs[cind])) { 6878 ++cind; 6879 continue; 6880 } 6881 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6882 } 6883 } 6884 } 6885 } 6886 *offset += fdof; 6887 PetscFunctionReturn(PETSC_SUCCESS); 6888 } 6889 6890 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[]) 6891 { 6892 PetscScalar *a; 6893 PetscInt fdof, foff, fcdof, foffset = *offset; 6894 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6895 PetscInt Nc, cind = 0, ncind = 0, b; 6896 PetscBool ncSet, fcSet; 6897 6898 PetscFunctionBegin; 6899 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6900 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6901 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6902 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6903 a = &array[foff]; 6904 if (fcdof) { 6905 /* We just override fcdof and fcdofs with Ncc and comps */ 6906 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6907 if (clperm) { 6908 if (perm) { 6909 if (comps) { 6910 for (b = 0; b < fdof; b++) { 6911 ncSet = fcSet = PETSC_FALSE; 6912 if (b % Nc == comps[ncind]) { 6913 ncind = (ncind + 1) % Ncc; 6914 ncSet = PETSC_TRUE; 6915 } 6916 if ((cind < fcdof) && (b == fcdofs[cind])) { 6917 ++cind; 6918 fcSet = PETSC_TRUE; 6919 } 6920 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6921 } 6922 } else { 6923 for (b = 0; b < fdof; b++) { 6924 if ((cind < fcdof) && (b == fcdofs[cind])) { 6925 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6926 ++cind; 6927 } 6928 } 6929 } 6930 } else { 6931 if (comps) { 6932 for (b = 0; b < fdof; b++) { 6933 ncSet = fcSet = PETSC_FALSE; 6934 if (b % Nc == comps[ncind]) { 6935 ncind = (ncind + 1) % Ncc; 6936 ncSet = PETSC_TRUE; 6937 } 6938 if ((cind < fcdof) && (b == fcdofs[cind])) { 6939 ++cind; 6940 fcSet = PETSC_TRUE; 6941 } 6942 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6943 } 6944 } else { 6945 for (b = 0; b < fdof; b++) { 6946 if ((cind < fcdof) && (b == fcdofs[cind])) { 6947 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6948 ++cind; 6949 } 6950 } 6951 } 6952 } 6953 } else { 6954 if (perm) { 6955 if (comps) { 6956 for (b = 0; b < fdof; b++) { 6957 ncSet = fcSet = PETSC_FALSE; 6958 if (b % Nc == comps[ncind]) { 6959 ncind = (ncind + 1) % Ncc; 6960 ncSet = PETSC_TRUE; 6961 } 6962 if ((cind < fcdof) && (b == fcdofs[cind])) { 6963 ++cind; 6964 fcSet = PETSC_TRUE; 6965 } 6966 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6967 } 6968 } else { 6969 for (b = 0; b < fdof; b++) { 6970 if ((cind < fcdof) && (b == fcdofs[cind])) { 6971 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6972 ++cind; 6973 } 6974 } 6975 } 6976 } else { 6977 if (comps) { 6978 for (b = 0; b < fdof; b++) { 6979 ncSet = fcSet = PETSC_FALSE; 6980 if (b % Nc == comps[ncind]) { 6981 ncind = (ncind + 1) % Ncc; 6982 ncSet = PETSC_TRUE; 6983 } 6984 if ((cind < fcdof) && (b == fcdofs[cind])) { 6985 ++cind; 6986 fcSet = PETSC_TRUE; 6987 } 6988 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6989 } 6990 } else { 6991 for (b = 0; b < fdof; b++) { 6992 if ((cind < fcdof) && (b == fcdofs[cind])) { 6993 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6994 ++cind; 6995 } 6996 } 6997 } 6998 } 6999 } 7000 } 7001 *offset += fdof; 7002 PetscFunctionReturn(PETSC_SUCCESS); 7003 } 7004 7005 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7006 { 7007 PetscScalar *array; 7008 const PetscInt *cone, *coneO; 7009 PetscInt pStart, pEnd, p, numPoints, off, dof; 7010 7011 PetscFunctionBeginHot; 7012 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7013 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7014 PetscCall(DMPlexGetCone(dm, point, &cone)); 7015 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7016 PetscCall(VecGetArray(v, &array)); 7017 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7018 const PetscInt cp = !p ? point : cone[p - 1]; 7019 const PetscInt o = !p ? 0 : coneO[p - 1]; 7020 7021 if ((cp < pStart) || (cp >= pEnd)) { 7022 dof = 0; 7023 continue; 7024 } 7025 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7026 /* ADD_VALUES */ 7027 { 7028 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7029 PetscScalar *a; 7030 PetscInt cdof, coff, cind = 0, k; 7031 7032 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7033 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7034 a = &array[coff]; 7035 if (!cdof) { 7036 if (o >= 0) { 7037 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7038 } else { 7039 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7040 } 7041 } else { 7042 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7043 if (o >= 0) { 7044 for (k = 0; k < dof; ++k) { 7045 if ((cind < cdof) && (k == cdofs[cind])) { 7046 ++cind; 7047 continue; 7048 } 7049 a[k] += values[off + k]; 7050 } 7051 } else { 7052 for (k = 0; k < dof; ++k) { 7053 if ((cind < cdof) && (k == cdofs[cind])) { 7054 ++cind; 7055 continue; 7056 } 7057 a[k] += values[off + dof - k - 1]; 7058 } 7059 } 7060 } 7061 } 7062 } 7063 PetscCall(VecRestoreArray(v, &array)); 7064 PetscFunctionReturn(PETSC_SUCCESS); 7065 } 7066 7067 /*@C 7068 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7069 7070 Not collective 7071 7072 Input Parameters: 7073 + dm - The `DM` 7074 . section - The section describing the layout in `v`, or `NULL` to use the default section 7075 . v - The local vector 7076 . point - The point in the `DM` 7077 . values - The array of values 7078 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7079 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7080 7081 Level: intermediate 7082 7083 Note: 7084 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7085 7086 Fortran Note: 7087 `values` must be declared with 7088 .vb 7089 PetscScalar,dimension(:),pointer :: values 7090 .ve 7091 7092 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7093 @*/ 7094 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7095 { 7096 PetscSection clSection; 7097 IS clPoints; 7098 PetscScalar *array; 7099 PetscInt *points = NULL; 7100 const PetscInt *clp, *clperm = NULL; 7101 PetscInt depth, numFields, numPoints, p, clsize; 7102 7103 PetscFunctionBeginHot; 7104 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7105 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7106 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7107 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7108 PetscCall(DMPlexGetDepth(dm, &depth)); 7109 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7110 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7111 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7112 PetscFunctionReturn(PETSC_SUCCESS); 7113 } 7114 /* Get points */ 7115 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7116 for (clsize = 0, p = 0; p < numPoints; p++) { 7117 PetscInt dof; 7118 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7119 clsize += dof; 7120 } 7121 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7122 /* Get array */ 7123 PetscCall(VecGetArray(v, &array)); 7124 /* Get values */ 7125 if (numFields > 0) { 7126 PetscInt offset = 0, f; 7127 for (f = 0; f < numFields; ++f) { 7128 const PetscInt **perms = NULL; 7129 const PetscScalar **flips = NULL; 7130 7131 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7132 switch (mode) { 7133 case INSERT_VALUES: 7134 for (p = 0; p < numPoints; p++) { 7135 const PetscInt point = points[2 * p]; 7136 const PetscInt *perm = perms ? perms[p] : NULL; 7137 const PetscScalar *flip = flips ? flips[p] : NULL; 7138 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7139 } 7140 break; 7141 case INSERT_ALL_VALUES: 7142 for (p = 0; p < numPoints; p++) { 7143 const PetscInt point = points[2 * p]; 7144 const PetscInt *perm = perms ? perms[p] : NULL; 7145 const PetscScalar *flip = flips ? flips[p] : NULL; 7146 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7147 } 7148 break; 7149 case INSERT_BC_VALUES: 7150 for (p = 0; p < numPoints; p++) { 7151 const PetscInt point = points[2 * p]; 7152 const PetscInt *perm = perms ? perms[p] : NULL; 7153 const PetscScalar *flip = flips ? flips[p] : NULL; 7154 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7155 } 7156 break; 7157 case ADD_VALUES: 7158 for (p = 0; p < numPoints; p++) { 7159 const PetscInt point = points[2 * p]; 7160 const PetscInt *perm = perms ? perms[p] : NULL; 7161 const PetscScalar *flip = flips ? flips[p] : NULL; 7162 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7163 } 7164 break; 7165 case ADD_ALL_VALUES: 7166 for (p = 0; p < numPoints; p++) { 7167 const PetscInt point = points[2 * p]; 7168 const PetscInt *perm = perms ? perms[p] : NULL; 7169 const PetscScalar *flip = flips ? flips[p] : NULL; 7170 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7171 } 7172 break; 7173 case ADD_BC_VALUES: 7174 for (p = 0; p < numPoints; p++) { 7175 const PetscInt point = points[2 * p]; 7176 const PetscInt *perm = perms ? perms[p] : NULL; 7177 const PetscScalar *flip = flips ? flips[p] : NULL; 7178 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7179 } 7180 break; 7181 default: 7182 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7183 } 7184 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7185 } 7186 } else { 7187 PetscInt dof, off; 7188 const PetscInt **perms = NULL; 7189 const PetscScalar **flips = NULL; 7190 7191 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7192 switch (mode) { 7193 case INSERT_VALUES: 7194 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7195 const PetscInt point = points[2 * p]; 7196 const PetscInt *perm = perms ? perms[p] : NULL; 7197 const PetscScalar *flip = flips ? flips[p] : NULL; 7198 PetscCall(PetscSectionGetDof(section, point, &dof)); 7199 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7200 } 7201 break; 7202 case INSERT_ALL_VALUES: 7203 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7204 const PetscInt point = points[2 * p]; 7205 const PetscInt *perm = perms ? perms[p] : NULL; 7206 const PetscScalar *flip = flips ? flips[p] : NULL; 7207 PetscCall(PetscSectionGetDof(section, point, &dof)); 7208 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7209 } 7210 break; 7211 case INSERT_BC_VALUES: 7212 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7213 const PetscInt point = points[2 * p]; 7214 const PetscInt *perm = perms ? perms[p] : NULL; 7215 const PetscScalar *flip = flips ? flips[p] : NULL; 7216 PetscCall(PetscSectionGetDof(section, point, &dof)); 7217 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7218 } 7219 break; 7220 case ADD_VALUES: 7221 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7222 const PetscInt point = points[2 * p]; 7223 const PetscInt *perm = perms ? perms[p] : NULL; 7224 const PetscScalar *flip = flips ? flips[p] : NULL; 7225 PetscCall(PetscSectionGetDof(section, point, &dof)); 7226 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7227 } 7228 break; 7229 case ADD_ALL_VALUES: 7230 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7231 const PetscInt point = points[2 * p]; 7232 const PetscInt *perm = perms ? perms[p] : NULL; 7233 const PetscScalar *flip = flips ? flips[p] : NULL; 7234 PetscCall(PetscSectionGetDof(section, point, &dof)); 7235 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7236 } 7237 break; 7238 case ADD_BC_VALUES: 7239 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7240 const PetscInt point = points[2 * p]; 7241 const PetscInt *perm = perms ? perms[p] : NULL; 7242 const PetscScalar *flip = flips ? flips[p] : NULL; 7243 PetscCall(PetscSectionGetDof(section, point, &dof)); 7244 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7245 } 7246 break; 7247 default: 7248 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7249 } 7250 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7251 } 7252 /* Cleanup points */ 7253 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7254 /* Cleanup array */ 7255 PetscCall(VecRestoreArray(v, &array)); 7256 PetscFunctionReturn(PETSC_SUCCESS); 7257 } 7258 7259 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7260 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7261 { 7262 PetscFunctionBegin; 7263 *contains = PETSC_TRUE; 7264 if (label) { 7265 PetscInt fdof; 7266 7267 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7268 if (!*contains) { 7269 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7270 *offset += fdof; 7271 PetscFunctionReturn(PETSC_SUCCESS); 7272 } 7273 } 7274 PetscFunctionReturn(PETSC_SUCCESS); 7275 } 7276 7277 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7278 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) 7279 { 7280 PetscSection clSection; 7281 IS clPoints; 7282 PetscScalar *array; 7283 PetscInt *points = NULL; 7284 const PetscInt *clp; 7285 PetscInt numFields, numPoints, p; 7286 PetscInt offset = 0, f; 7287 7288 PetscFunctionBeginHot; 7289 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7290 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7291 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7292 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7293 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7294 /* Get points */ 7295 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7296 /* Get array */ 7297 PetscCall(VecGetArray(v, &array)); 7298 /* Get values */ 7299 for (f = 0; f < numFields; ++f) { 7300 const PetscInt **perms = NULL; 7301 const PetscScalar **flips = NULL; 7302 PetscBool contains; 7303 7304 if (!fieldActive[f]) { 7305 for (p = 0; p < numPoints * 2; p += 2) { 7306 PetscInt fdof; 7307 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7308 offset += fdof; 7309 } 7310 continue; 7311 } 7312 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7313 switch (mode) { 7314 case INSERT_VALUES: 7315 for (p = 0; p < numPoints; p++) { 7316 const PetscInt point = points[2 * p]; 7317 const PetscInt *perm = perms ? perms[p] : NULL; 7318 const PetscScalar *flip = flips ? flips[p] : NULL; 7319 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7320 if (!contains) continue; 7321 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7322 } 7323 break; 7324 case INSERT_ALL_VALUES: 7325 for (p = 0; p < numPoints; p++) { 7326 const PetscInt point = points[2 * p]; 7327 const PetscInt *perm = perms ? perms[p] : NULL; 7328 const PetscScalar *flip = flips ? flips[p] : NULL; 7329 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7330 if (!contains) continue; 7331 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7332 } 7333 break; 7334 case INSERT_BC_VALUES: 7335 for (p = 0; p < numPoints; p++) { 7336 const PetscInt point = points[2 * p]; 7337 const PetscInt *perm = perms ? perms[p] : NULL; 7338 const PetscScalar *flip = flips ? flips[p] : NULL; 7339 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7340 if (!contains) continue; 7341 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7342 } 7343 break; 7344 case ADD_VALUES: 7345 for (p = 0; p < numPoints; p++) { 7346 const PetscInt point = points[2 * p]; 7347 const PetscInt *perm = perms ? perms[p] : NULL; 7348 const PetscScalar *flip = flips ? flips[p] : NULL; 7349 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7350 if (!contains) continue; 7351 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7352 } 7353 break; 7354 case ADD_ALL_VALUES: 7355 for (p = 0; p < numPoints; p++) { 7356 const PetscInt point = points[2 * p]; 7357 const PetscInt *perm = perms ? perms[p] : NULL; 7358 const PetscScalar *flip = flips ? flips[p] : NULL; 7359 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7360 if (!contains) continue; 7361 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7362 } 7363 break; 7364 default: 7365 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7366 } 7367 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7368 } 7369 /* Cleanup points */ 7370 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7371 /* Cleanup array */ 7372 PetscCall(VecRestoreArray(v, &array)); 7373 PetscFunctionReturn(PETSC_SUCCESS); 7374 } 7375 7376 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7377 { 7378 PetscMPIInt rank; 7379 PetscInt i, j; 7380 7381 PetscFunctionBegin; 7382 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7383 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7384 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7385 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7386 numCIndices = numCIndices ? numCIndices : numRIndices; 7387 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7388 for (i = 0; i < numRIndices; i++) { 7389 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7390 for (j = 0; j < numCIndices; j++) { 7391 #if defined(PETSC_USE_COMPLEX) 7392 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7393 #else 7394 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7395 #endif 7396 } 7397 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7398 } 7399 PetscFunctionReturn(PETSC_SUCCESS); 7400 } 7401 7402 /* 7403 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7404 7405 Input Parameters: 7406 + section - The section for this data layout 7407 . islocal - Is the section (and thus indices being requested) local or global? 7408 . point - The point contributing dofs with these indices 7409 . off - The global offset of this point 7410 . loff - The local offset of each field 7411 . setBC - The flag determining whether to include indices of boundary values 7412 . perm - A permutation of the dofs on this point, or NULL 7413 - indperm - A permutation of the entire indices array, or NULL 7414 7415 Output Parameter: 7416 . indices - Indices for dofs on this point 7417 7418 Level: developer 7419 7420 Note: The indices could be local or global, depending on the value of 'off'. 7421 */ 7422 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7423 { 7424 PetscInt dof; /* The number of unknowns on this point */ 7425 PetscInt cdof; /* The number of constraints on this point */ 7426 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7427 PetscInt cind = 0, k; 7428 7429 PetscFunctionBegin; 7430 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7431 PetscCall(PetscSectionGetDof(section, point, &dof)); 7432 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7433 if (!cdof || setBC) { 7434 for (k = 0; k < dof; ++k) { 7435 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7436 const PetscInt ind = indperm ? indperm[preind] : preind; 7437 7438 indices[ind] = off + k; 7439 } 7440 } else { 7441 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7442 for (k = 0; k < dof; ++k) { 7443 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7444 const PetscInt ind = indperm ? indperm[preind] : preind; 7445 7446 if ((cind < cdof) && (k == cdofs[cind])) { 7447 /* Insert check for returning constrained indices */ 7448 indices[ind] = -(off + k + 1); 7449 ++cind; 7450 } else { 7451 indices[ind] = off + k - (islocal ? 0 : cind); 7452 } 7453 } 7454 } 7455 *loff += dof; 7456 PetscFunctionReturn(PETSC_SUCCESS); 7457 } 7458 7459 /* 7460 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7461 7462 Input Parameters: 7463 + section - a section (global or local) 7464 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7465 . point - point within section 7466 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7467 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7468 . setBC - identify constrained (boundary condition) points via involution. 7469 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7470 . permsoff - offset 7471 - indperm - index permutation 7472 7473 Output Parameter: 7474 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7475 . indices - array to hold indices (as defined by section) of each dof associated with point 7476 7477 Notes: 7478 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7479 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7480 in the local vector. 7481 7482 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7483 significant). It is invalid to call with a global section and setBC=true. 7484 7485 Developer Note: 7486 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7487 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7488 offset could be obtained from the section instead of passing it explicitly as we do now. 7489 7490 Example: 7491 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7492 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7493 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7494 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. 7495 7496 Level: developer 7497 */ 7498 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[]) 7499 { 7500 PetscInt numFields, foff, f; 7501 7502 PetscFunctionBegin; 7503 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7504 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7505 for (f = 0, foff = 0; f < numFields; ++f) { 7506 PetscInt fdof, cfdof; 7507 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7508 PetscInt cind = 0, b; 7509 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7510 7511 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7512 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7513 if (!cfdof || setBC) { 7514 for (b = 0; b < fdof; ++b) { 7515 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7516 const PetscInt ind = indperm ? indperm[preind] : preind; 7517 7518 indices[ind] = off + foff + b; 7519 } 7520 } else { 7521 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7522 for (b = 0; b < fdof; ++b) { 7523 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7524 const PetscInt ind = indperm ? indperm[preind] : preind; 7525 7526 if ((cind < cfdof) && (b == fcdofs[cind])) { 7527 indices[ind] = -(off + foff + b + 1); 7528 ++cind; 7529 } else { 7530 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7531 } 7532 } 7533 } 7534 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7535 foffs[f] += fdof; 7536 } 7537 PetscFunctionReturn(PETSC_SUCCESS); 7538 } 7539 7540 /* 7541 This version believes the globalSection offsets for each field, rather than just the point offset 7542 7543 . foffs - The offset into 'indices' for each field, since it is segregated by field 7544 7545 Notes: 7546 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7547 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7548 */ 7549 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7550 { 7551 PetscInt numFields, foff, f; 7552 7553 PetscFunctionBegin; 7554 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7555 for (f = 0; f < numFields; ++f) { 7556 PetscInt fdof, cfdof; 7557 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7558 PetscInt cind = 0, b; 7559 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7560 7561 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7562 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7563 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7564 if (!cfdof) { 7565 for (b = 0; b < fdof; ++b) { 7566 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7567 const PetscInt ind = indperm ? indperm[preind] : preind; 7568 7569 indices[ind] = foff + b; 7570 } 7571 } else { 7572 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7573 for (b = 0; b < fdof; ++b) { 7574 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7575 const PetscInt ind = indperm ? indperm[preind] : preind; 7576 7577 if ((cind < cfdof) && (b == fcdofs[cind])) { 7578 indices[ind] = -(foff + b + 1); 7579 ++cind; 7580 } else { 7581 indices[ind] = foff + b - cind; 7582 } 7583 } 7584 } 7585 foffs[f] += fdof; 7586 } 7587 PetscFunctionReturn(PETSC_SUCCESS); 7588 } 7589 7590 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7591 { 7592 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7593 7594 PetscFunctionBegin; 7595 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7596 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7597 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7598 for (PetscInt p = 0; p < nPoints; p++) { 7599 PetscInt b = pnts[2 * p]; 7600 PetscInt bSecDof = 0, bOff; 7601 PetscInt cSecDof = 0; 7602 PetscSection indices_section; 7603 7604 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7605 if (!bSecDof) continue; 7606 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7607 indices_section = cSecDof > 0 ? cSec : section; 7608 if (numFields) { 7609 PetscInt fStart[32], fEnd[32]; 7610 7611 fStart[0] = 0; 7612 fEnd[0] = 0; 7613 for (PetscInt f = 0; f < numFields; f++) { 7614 PetscInt fDof = 0; 7615 7616 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7617 fStart[f + 1] = fStart[f] + fDof; 7618 fEnd[f + 1] = fStart[f + 1]; 7619 } 7620 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7621 // only apply permutations on one side 7622 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7623 for (PetscInt f = 0; f < numFields; f++) { 7624 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7625 } 7626 } else { 7627 PetscInt bEnd = 0; 7628 7629 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7630 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7631 7632 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7633 } 7634 } 7635 PetscFunctionReturn(PETSC_SUCCESS); 7636 } 7637 7638 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[]) 7639 { 7640 Mat cMat; 7641 PetscSection aSec, cSec; 7642 IS aIS; 7643 PetscInt aStart = -1, aEnd = -1; 7644 PetscInt sStart = -1, sEnd = -1; 7645 PetscInt cStart = -1, cEnd = -1; 7646 const PetscInt *anchors; 7647 PetscInt numFields, p; 7648 PetscInt newNumPoints = 0, newNumIndices = 0; 7649 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7650 PetscInt oldOffsets[32]; 7651 PetscInt newOffsets[32]; 7652 PetscInt oldOffsetsCopy[32]; 7653 PetscInt newOffsetsCopy[32]; 7654 PetscScalar *modMat = NULL; 7655 PetscBool anyConstrained = PETSC_FALSE; 7656 7657 PetscFunctionBegin; 7658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7659 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7660 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7661 7662 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7663 /* if there are point-to-point constraints */ 7664 if (aSec) { 7665 PetscCall(PetscArrayzero(newOffsets, 32)); 7666 PetscCall(PetscArrayzero(oldOffsets, 32)); 7667 PetscCall(ISGetIndices(aIS, &anchors)); 7668 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7669 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7670 /* figure out how many points are going to be in the new element matrix 7671 * (we allow double counting, because it's all just going to be summed 7672 * into the global matrix anyway) */ 7673 for (p = 0; p < 2 * numPoints; p += 2) { 7674 PetscInt b = points[p]; 7675 PetscInt bDof = 0, bSecDof = 0; 7676 7677 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7678 if (!bSecDof) continue; 7679 7680 for (PetscInt f = 0; f < numFields; f++) { 7681 PetscInt fDof = 0; 7682 7683 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7684 oldOffsets[f + 1] += fDof; 7685 } 7686 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7687 if (bDof) { 7688 /* this point is constrained */ 7689 /* it is going to be replaced by its anchors */ 7690 PetscInt bOff, q; 7691 7692 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7693 for (q = 0; q < bDof; q++) { 7694 PetscInt a = anchors[bOff + q]; 7695 PetscInt aDof = 0; 7696 7697 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7698 if (aDof) { 7699 anyConstrained = PETSC_TRUE; 7700 newNumPoints += 1; 7701 } 7702 newNumIndices += aDof; 7703 for (PetscInt f = 0; f < numFields; ++f) { 7704 PetscInt fDof = 0; 7705 7706 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7707 newOffsets[f + 1] += fDof; 7708 } 7709 } 7710 } else { 7711 /* this point is not constrained */ 7712 newNumPoints++; 7713 newNumIndices += bSecDof; 7714 for (PetscInt f = 0; f < numFields; ++f) { 7715 PetscInt fDof; 7716 7717 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7718 newOffsets[f + 1] += fDof; 7719 } 7720 } 7721 } 7722 } 7723 if (!anyConstrained) { 7724 if (outNumPoints) *outNumPoints = 0; 7725 if (outNumIndices) *outNumIndices = 0; 7726 if (outPoints) *outPoints = NULL; 7727 if (outMat) *outMat = NULL; 7728 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7729 PetscFunctionReturn(PETSC_SUCCESS); 7730 } 7731 7732 if (outNumPoints) *outNumPoints = newNumPoints; 7733 if (outNumIndices) *outNumIndices = newNumIndices; 7734 7735 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7736 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7737 7738 if (!outPoints && !outMat) { 7739 if (offsets) { 7740 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7741 } 7742 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7743 PetscFunctionReturn(PETSC_SUCCESS); 7744 } 7745 7746 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7747 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7748 7749 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7750 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7751 7752 /* output arrays */ 7753 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7754 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7755 7756 // get the new Points 7757 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7758 PetscInt b = points[2 * p]; 7759 PetscInt bDof = 0, bSecDof = 0, bOff; 7760 7761 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7762 if (!bSecDof) continue; 7763 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7764 if (bDof) { 7765 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7766 for (PetscInt q = 0; q < bDof; q++) { 7767 PetscInt a = anchors[bOff + q], aDof = 0; 7768 7769 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7770 if (aDof) { 7771 newPoints[2 * newP] = a; 7772 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7773 newP++; 7774 } 7775 } 7776 } else { 7777 newPoints[2 * newP] = b; 7778 newPoints[2 * newP + 1] = points[2 * p + 1]; 7779 newP++; 7780 } 7781 } 7782 7783 if (outMat) { 7784 PetscScalar *tmpMat; 7785 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7786 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7787 7788 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7789 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7790 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7791 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7792 7793 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7794 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7795 7796 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7797 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7798 7799 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7800 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7801 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7802 // for each field, insert the anchor modification into modMat 7803 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7804 PetscInt fStart = oldOffsets[f]; 7805 PetscInt fNewStart = newOffsets[f]; 7806 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7807 PetscInt b = points[2 * p]; 7808 PetscInt bDof = 0, bSecDof = 0, bOff; 7809 7810 if (b >= sStart && b < sEnd) { 7811 if (numFields) { 7812 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7813 } else { 7814 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7815 } 7816 } 7817 if (!bSecDof) continue; 7818 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7819 if (bDof) { 7820 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7821 for (PetscInt q = 0; q < bDof; q++, newP++) { 7822 PetscInt a = anchors[bOff + q], aDof = 0; 7823 7824 if (a >= sStart && a < sEnd) { 7825 if (numFields) { 7826 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7827 } else { 7828 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7829 } 7830 } 7831 if (aDof) { 7832 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7833 for (PetscInt d = 0; d < bSecDof; d++) { 7834 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7835 } 7836 } 7837 oNew += aDof; 7838 } 7839 } else { 7840 // Insert the identity matrix in this block 7841 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7842 oNew += bSecDof; 7843 newP++; 7844 } 7845 o += bSecDof; 7846 } 7847 } 7848 7849 *outMat = modMat; 7850 7851 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7852 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7853 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7854 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7855 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7856 } 7857 PetscCall(ISRestoreIndices(aIS, &anchors)); 7858 7859 /* output */ 7860 if (outPoints) { 7861 *outPoints = newPoints; 7862 } else { 7863 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7864 } 7865 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7866 PetscFunctionReturn(PETSC_SUCCESS); 7867 } 7868 7869 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) 7870 { 7871 PetscScalar *modMat = NULL; 7872 PetscInt newNumIndices = -1; 7873 7874 PetscFunctionBegin; 7875 /* 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. 7876 modMat is that matrix C */ 7877 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7878 if (outNumIndices) *outNumIndices = newNumIndices; 7879 if (modMat) { 7880 const PetscScalar *newValues = values; 7881 7882 if (multiplyRight) { 7883 PetscScalar *newNewValues = NULL; 7884 PetscBLASInt M = newNumIndices; 7885 PetscBLASInt N = numRows; 7886 PetscBLASInt K = numIndices; 7887 PetscScalar a = 1.0, b = 0.0; 7888 7889 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); 7890 7891 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7892 // row-major to column-major conversion, right multiplication becomes left multiplication 7893 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7894 7895 numCols = newNumIndices; 7896 newValues = newNewValues; 7897 } 7898 7899 if (multiplyLeft) { 7900 PetscScalar *newNewValues = NULL; 7901 PetscBLASInt M = numCols; 7902 PetscBLASInt N = newNumIndices; 7903 PetscBLASInt K = numIndices; 7904 PetscScalar a = 1.0, b = 0.0; 7905 7906 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); 7907 7908 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7909 // row-major to column-major conversion, left multiplication becomes right multiplication 7910 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7911 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7912 newValues = newNewValues; 7913 } 7914 *outValues = (PetscScalar *)newValues; 7915 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7916 } 7917 PetscFunctionReturn(PETSC_SUCCESS); 7918 } 7919 7920 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) 7921 { 7922 PetscFunctionBegin; 7923 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7924 PetscFunctionReturn(PETSC_SUCCESS); 7925 } 7926 7927 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7928 { 7929 /* Closure ordering */ 7930 PetscSection clSection; 7931 IS clPoints; 7932 const PetscInt *clp; 7933 PetscInt *points; 7934 PetscInt Ncl, Ni = 0; 7935 7936 PetscFunctionBeginHot; 7937 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7938 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7939 PetscInt dof; 7940 7941 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7942 Ni += dof; 7943 } 7944 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7945 *closureSize = Ni; 7946 PetscFunctionReturn(PETSC_SUCCESS); 7947 } 7948 7949 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) 7950 { 7951 /* Closure ordering */ 7952 PetscSection clSection; 7953 IS clPoints; 7954 const PetscInt *clp; 7955 PetscInt *points; 7956 const PetscInt *clperm = NULL; 7957 /* Dof permutation and sign flips */ 7958 const PetscInt **perms[32] = {NULL}; 7959 const PetscScalar **flips[32] = {NULL}; 7960 PetscScalar *valCopy = NULL; 7961 /* Hanging node constraints */ 7962 PetscInt *pointsC = NULL; 7963 PetscScalar *valuesC = NULL; 7964 PetscInt NclC, NiC; 7965 7966 PetscInt *idx; 7967 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7968 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7969 PetscInt idxStart, idxEnd; 7970 PetscInt nRows, nCols; 7971 7972 PetscFunctionBeginHot; 7973 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7974 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7975 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7976 PetscAssertPointer(numRows, 6); 7977 PetscAssertPointer(numCols, 7); 7978 if (indices) PetscAssertPointer(indices, 8); 7979 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7980 if (values) PetscAssertPointer(values, 10); 7981 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7982 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7983 PetscCall(PetscArrayzero(offsets, 32)); 7984 /* 1) Get points in closure */ 7985 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7986 if (useClPerm) { 7987 PetscInt depth, clsize; 7988 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7989 for (clsize = 0, p = 0; p < Ncl; p++) { 7990 PetscInt dof; 7991 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7992 clsize += dof; 7993 } 7994 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7995 } 7996 /* 2) Get number of indices on these points and field offsets from section */ 7997 for (p = 0; p < Ncl * 2; p += 2) { 7998 PetscInt dof, fdof; 7999 8000 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8001 for (f = 0; f < Nf; ++f) { 8002 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8003 offsets[f + 1] += fdof; 8004 } 8005 Ni += dof; 8006 } 8007 if (*numRows == -1) *numRows = Ni; 8008 if (*numCols == -1) *numCols = Ni; 8009 nRows = *numRows; 8010 nCols = *numCols; 8011 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8012 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8013 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8014 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8015 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8016 for (f = 0; f < PetscMax(1, Nf); ++f) { 8017 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8018 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8019 /* may need to apply sign changes to the element matrix */ 8020 if (values && flips[f]) { 8021 PetscInt foffset = offsets[f]; 8022 8023 for (p = 0; p < Ncl; ++p) { 8024 PetscInt pnt = points[2 * p], fdof; 8025 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8026 8027 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8028 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8029 if (flip) { 8030 PetscInt i, j, k; 8031 8032 if (!valCopy) { 8033 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8034 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8035 *values = valCopy; 8036 } 8037 for (i = 0; i < fdof; ++i) { 8038 PetscScalar fval = flip[i]; 8039 8040 if (multiplyRight) { 8041 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8042 } 8043 if (multiplyLeft) { 8044 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8045 } 8046 } 8047 } 8048 foffset += fdof; 8049 } 8050 } 8051 } 8052 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8053 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8054 if (NclC) { 8055 if (multiplyRight) { *numCols = nCols = NiC; } 8056 if (multiplyLeft) { *numRows = nRows = NiC; } 8057 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8058 for (f = 0; f < PetscMax(1, Nf); ++f) { 8059 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8060 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8061 } 8062 for (f = 0; f < PetscMax(1, Nf); ++f) { 8063 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8064 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8065 } 8066 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8067 Ncl = NclC; 8068 Ni = NiC; 8069 points = pointsC; 8070 if (values) *values = valuesC; 8071 } 8072 /* 5) Calculate indices */ 8073 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8074 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8075 if (Nf) { 8076 PetscInt idxOff; 8077 PetscBool useFieldOffsets; 8078 8079 if (outOffsets) { 8080 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8081 } 8082 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8083 if (useFieldOffsets) { 8084 for (p = 0; p < Ncl; ++p) { 8085 const PetscInt pnt = points[p * 2]; 8086 8087 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8088 } 8089 } else { 8090 for (p = 0; p < Ncl; ++p) { 8091 const PetscInt pnt = points[p * 2]; 8092 8093 if (pnt < idxStart || pnt >= idxEnd) continue; 8094 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8095 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8096 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8097 * global section. */ 8098 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8099 } 8100 } 8101 } else { 8102 PetscInt off = 0, idxOff; 8103 8104 for (p = 0; p < Ncl; ++p) { 8105 const PetscInt pnt = points[p * 2]; 8106 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8107 8108 if (pnt < idxStart || pnt >= idxEnd) continue; 8109 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8110 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8111 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8112 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8113 } 8114 } 8115 /* 6) Cleanup */ 8116 for (f = 0; f < PetscMax(1, Nf); ++f) { 8117 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8118 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8119 } 8120 if (NclC) { 8121 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8122 } else { 8123 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8124 } 8125 8126 if (indices) *indices = idx; 8127 PetscFunctionReturn(PETSC_SUCCESS); 8128 } 8129 8130 /*@C 8131 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8132 8133 Not collective 8134 8135 Input Parameters: 8136 + dm - The `DM` 8137 . section - The `PetscSection` describing the points (a local section) 8138 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8139 . point - The point defining the closure 8140 - useClPerm - Use the closure point permutation if available 8141 8142 Output Parameters: 8143 + numIndices - The number of dof indices in the closure of point with the input sections 8144 . indices - The dof indices 8145 . outOffsets - Array to write the field offsets into, or `NULL` 8146 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8147 8148 Level: advanced 8149 8150 Notes: 8151 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8152 8153 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8154 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8155 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8156 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8157 indices (with the above semantics) are implied. 8158 8159 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8160 `PetscSection`, `DMGetGlobalSection()` 8161 @*/ 8162 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8163 { 8164 PetscInt numRows = -1, numCols = -1; 8165 8166 PetscFunctionBeginHot; 8167 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8168 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8169 *numIndices = numRows; 8170 PetscFunctionReturn(PETSC_SUCCESS); 8171 } 8172 8173 /*@C 8174 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8175 8176 Not collective 8177 8178 Input Parameters: 8179 + dm - The `DM` 8180 . section - The `PetscSection` describing the points (a local section) 8181 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8182 . point - The point defining the closure 8183 - useClPerm - Use the closure point permutation if available 8184 8185 Output Parameters: 8186 + numIndices - The number of dof indices in the closure of point with the input sections 8187 . indices - The dof indices 8188 . outOffsets - Array to write the field offsets into, or `NULL` 8189 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8190 8191 Level: advanced 8192 8193 Notes: 8194 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8195 8196 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8197 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8198 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8199 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8200 indices (with the above semantics) are implied. 8201 8202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8203 @*/ 8204 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8205 { 8206 PetscFunctionBegin; 8207 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8208 PetscAssertPointer(indices, 7); 8209 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8210 PetscFunctionReturn(PETSC_SUCCESS); 8211 } 8212 8213 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8214 { 8215 DM_Plex *mesh = (DM_Plex *)dm->data; 8216 PetscInt *indices; 8217 PetscInt numIndices; 8218 const PetscScalar *valuesOrig = values; 8219 PetscErrorCode ierr; 8220 8221 PetscFunctionBegin; 8222 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8223 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8224 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8225 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8226 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8227 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8228 8229 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8230 8231 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8232 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8233 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8234 if (ierr) { 8235 PetscMPIInt rank; 8236 8237 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8238 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8239 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8240 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8241 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8242 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8243 } 8244 if (mesh->printFEM > 1) { 8245 PetscInt i; 8246 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8247 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8248 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8249 } 8250 8251 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8252 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8253 PetscFunctionReturn(PETSC_SUCCESS); 8254 } 8255 8256 /*@C 8257 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8258 8259 Not collective 8260 8261 Input Parameters: 8262 + dm - The `DM` 8263 . section - The section describing the layout in `v`, or `NULL` to use the default section 8264 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8265 . A - The matrix 8266 . point - The point in the `DM` 8267 . values - The array of values 8268 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8269 8270 Level: intermediate 8271 8272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8273 @*/ 8274 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8275 { 8276 PetscFunctionBegin; 8277 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8278 PetscFunctionReturn(PETSC_SUCCESS); 8279 } 8280 8281 /*@C 8282 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8283 8284 Not collective 8285 8286 Input Parameters: 8287 + dmRow - The `DM` for the row fields 8288 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8289 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8290 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8291 . dmCol - The `DM` for the column fields 8292 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8293 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8294 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8295 . A - The matrix 8296 . point - The point in the `DM` 8297 . values - The array of values 8298 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8299 8300 Level: intermediate 8301 8302 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8303 @*/ 8304 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) 8305 { 8306 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8307 PetscInt *indicesRow, *indicesCol; 8308 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8309 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8310 8311 PetscErrorCode ierr; 8312 8313 PetscFunctionBegin; 8314 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8315 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8316 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8317 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8318 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8319 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8320 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8321 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8322 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8323 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8324 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8325 8326 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8327 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8328 valuesV1 = valuesV0; 8329 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8330 valuesV2 = valuesV1; 8331 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8332 8333 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8334 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8335 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8336 if (ierr) { 8337 PetscMPIInt rank; 8338 8339 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8340 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8341 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8342 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8343 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8344 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8345 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8346 } 8347 8348 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8349 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8350 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8351 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8352 PetscFunctionReturn(PETSC_SUCCESS); 8353 } 8354 8355 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8356 { 8357 DM_Plex *mesh = (DM_Plex *)dmf->data; 8358 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8359 PetscInt *cpoints = NULL; 8360 PetscInt *findices, *cindices; 8361 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8362 PetscInt foffsets[32], coffsets[32]; 8363 DMPolytopeType ct; 8364 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8365 PetscErrorCode ierr; 8366 8367 PetscFunctionBegin; 8368 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8369 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8370 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8371 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8372 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8373 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8374 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8375 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8376 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8377 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8378 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8379 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8380 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8381 PetscCall(PetscArrayzero(foffsets, 32)); 8382 PetscCall(PetscArrayzero(coffsets, 32)); 8383 /* Column indices */ 8384 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8385 maxFPoints = numCPoints; 8386 /* Compress out points not in the section */ 8387 /* TODO: Squeeze out points with 0 dof as well */ 8388 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8389 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8390 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8391 cpoints[q * 2] = cpoints[p]; 8392 cpoints[q * 2 + 1] = cpoints[p + 1]; 8393 ++q; 8394 } 8395 } 8396 numCPoints = q; 8397 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8398 PetscInt fdof; 8399 8400 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8401 if (!dof) continue; 8402 for (f = 0; f < numFields; ++f) { 8403 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8404 coffsets[f + 1] += fdof; 8405 } 8406 numCIndices += dof; 8407 } 8408 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8409 /* Row indices */ 8410 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8411 { 8412 DMPlexTransform tr; 8413 DMPolytopeType *rct; 8414 PetscInt *rsize, *rcone, *rornt, Nt; 8415 8416 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8417 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8418 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8419 numSubcells = rsize[Nt - 1]; 8420 PetscCall(DMPlexTransformDestroy(&tr)); 8421 } 8422 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8423 for (r = 0, q = 0; r < numSubcells; ++r) { 8424 /* TODO Map from coarse to fine cells */ 8425 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8426 /* Compress out points not in the section */ 8427 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8428 for (p = 0; p < numFPoints * 2; p += 2) { 8429 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8430 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8431 if (!dof) continue; 8432 for (s = 0; s < q; ++s) 8433 if (fpoints[p] == ftotpoints[s * 2]) break; 8434 if (s < q) continue; 8435 ftotpoints[q * 2] = fpoints[p]; 8436 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8437 ++q; 8438 } 8439 } 8440 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8441 } 8442 numFPoints = q; 8443 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8444 PetscInt fdof; 8445 8446 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8447 if (!dof) continue; 8448 for (f = 0; f < numFields; ++f) { 8449 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8450 foffsets[f + 1] += fdof; 8451 } 8452 numFIndices += dof; 8453 } 8454 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8455 8456 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8457 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8458 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8459 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8460 if (numFields) { 8461 const PetscInt **permsF[32] = {NULL}; 8462 const PetscInt **permsC[32] = {NULL}; 8463 8464 for (f = 0; f < numFields; f++) { 8465 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8466 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8467 } 8468 for (p = 0; p < numFPoints; p++) { 8469 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8470 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8471 } 8472 for (p = 0; p < numCPoints; p++) { 8473 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8474 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8475 } 8476 for (f = 0; f < numFields; f++) { 8477 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8478 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8479 } 8480 } else { 8481 const PetscInt **permsF = NULL; 8482 const PetscInt **permsC = NULL; 8483 8484 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8485 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8486 for (p = 0, off = 0; p < numFPoints; p++) { 8487 const PetscInt *perm = permsF ? permsF[p] : NULL; 8488 8489 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8490 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8491 } 8492 for (p = 0, off = 0; p < numCPoints; p++) { 8493 const PetscInt *perm = permsC ? permsC[p] : NULL; 8494 8495 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8496 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8497 } 8498 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8499 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8500 } 8501 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8502 /* TODO: flips */ 8503 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8504 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8505 if (ierr) { 8506 PetscMPIInt rank; 8507 8508 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8509 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8510 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8511 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8512 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8513 } 8514 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8515 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8516 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8517 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8518 PetscFunctionReturn(PETSC_SUCCESS); 8519 } 8520 8521 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8522 { 8523 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8524 PetscInt *cpoints = NULL; 8525 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8526 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8527 DMPolytopeType ct; 8528 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8529 8530 PetscFunctionBegin; 8531 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8532 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8533 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8534 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8535 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8536 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8537 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8538 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8539 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8540 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8541 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8542 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8543 /* Column indices */ 8544 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8545 maxFPoints = numCPoints; 8546 /* Compress out points not in the section */ 8547 /* TODO: Squeeze out points with 0 dof as well */ 8548 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8549 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8550 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8551 cpoints[q * 2] = cpoints[p]; 8552 cpoints[q * 2 + 1] = cpoints[p + 1]; 8553 ++q; 8554 } 8555 } 8556 numCPoints = q; 8557 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8558 PetscInt fdof; 8559 8560 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8561 if (!dof) continue; 8562 for (f = 0; f < numFields; ++f) { 8563 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8564 coffsets[f + 1] += fdof; 8565 } 8566 numCIndices += dof; 8567 } 8568 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8569 /* Row indices */ 8570 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8571 { 8572 DMPlexTransform tr; 8573 DMPolytopeType *rct; 8574 PetscInt *rsize, *rcone, *rornt, Nt; 8575 8576 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8577 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8578 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8579 numSubcells = rsize[Nt - 1]; 8580 PetscCall(DMPlexTransformDestroy(&tr)); 8581 } 8582 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8583 for (r = 0, q = 0; r < numSubcells; ++r) { 8584 /* TODO Map from coarse to fine cells */ 8585 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8586 /* Compress out points not in the section */ 8587 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8588 for (p = 0; p < numFPoints * 2; p += 2) { 8589 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8590 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8591 if (!dof) continue; 8592 for (s = 0; s < q; ++s) 8593 if (fpoints[p] == ftotpoints[s * 2]) break; 8594 if (s < q) continue; 8595 ftotpoints[q * 2] = fpoints[p]; 8596 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8597 ++q; 8598 } 8599 } 8600 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8601 } 8602 numFPoints = q; 8603 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8604 PetscInt fdof; 8605 8606 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8607 if (!dof) continue; 8608 for (f = 0; f < numFields; ++f) { 8609 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8610 foffsets[f + 1] += fdof; 8611 } 8612 numFIndices += dof; 8613 } 8614 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8615 8616 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8617 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8618 if (numFields) { 8619 const PetscInt **permsF[32] = {NULL}; 8620 const PetscInt **permsC[32] = {NULL}; 8621 8622 for (f = 0; f < numFields; f++) { 8623 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8624 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8625 } 8626 for (p = 0; p < numFPoints; p++) { 8627 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8628 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8629 } 8630 for (p = 0; p < numCPoints; p++) { 8631 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8632 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8633 } 8634 for (f = 0; f < numFields; f++) { 8635 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8636 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8637 } 8638 } else { 8639 const PetscInt **permsF = NULL; 8640 const PetscInt **permsC = NULL; 8641 8642 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8643 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8644 for (p = 0, off = 0; p < numFPoints; p++) { 8645 const PetscInt *perm = permsF ? permsF[p] : NULL; 8646 8647 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8648 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8649 } 8650 for (p = 0, off = 0; p < numCPoints; p++) { 8651 const PetscInt *perm = permsC ? permsC[p] : NULL; 8652 8653 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8654 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8655 } 8656 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8657 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8658 } 8659 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8660 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8661 PetscFunctionReturn(PETSC_SUCCESS); 8662 } 8663 8664 /*@ 8665 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8666 8667 Input Parameter: 8668 . dm - The `DMPLEX` object 8669 8670 Output Parameter: 8671 . cellHeight - The height of a cell 8672 8673 Level: developer 8674 8675 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8676 @*/ 8677 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8678 { 8679 DM_Plex *mesh = (DM_Plex *)dm->data; 8680 8681 PetscFunctionBegin; 8682 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8683 PetscAssertPointer(cellHeight, 2); 8684 *cellHeight = mesh->vtkCellHeight; 8685 PetscFunctionReturn(PETSC_SUCCESS); 8686 } 8687 8688 /*@ 8689 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8690 8691 Input Parameters: 8692 + dm - The `DMPLEX` object 8693 - cellHeight - The height of a cell 8694 8695 Level: developer 8696 8697 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8698 @*/ 8699 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8700 { 8701 DM_Plex *mesh = (DM_Plex *)dm->data; 8702 8703 PetscFunctionBegin; 8704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8705 mesh->vtkCellHeight = cellHeight; 8706 PetscFunctionReturn(PETSC_SUCCESS); 8707 } 8708 8709 /*@ 8710 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8711 8712 Input Parameters: 8713 + dm - The `DMPLEX` object 8714 - ct - The `DMPolytopeType` of the cell 8715 8716 Output Parameters: 8717 + start - The first cell of this type, or `NULL` 8718 - end - The upper bound on this celltype, or `NULL` 8719 8720 Level: advanced 8721 8722 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8723 @*/ 8724 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8725 { 8726 DM_Plex *mesh = (DM_Plex *)dm->data; 8727 DMLabel label; 8728 PetscInt pStart, pEnd; 8729 8730 PetscFunctionBegin; 8731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8732 if (start) { 8733 PetscAssertPointer(start, 3); 8734 *start = 0; 8735 } 8736 if (end) { 8737 PetscAssertPointer(end, 4); 8738 *end = 0; 8739 } 8740 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8741 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8742 if (mesh->tr) { 8743 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8744 } else { 8745 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8746 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8747 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8748 } 8749 PetscFunctionReturn(PETSC_SUCCESS); 8750 } 8751 8752 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8753 { 8754 PetscSection section, globalSection; 8755 PetscInt *numbers, p; 8756 8757 PetscFunctionBegin; 8758 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8759 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8760 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8761 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8762 PetscCall(PetscSectionSetUp(section)); 8763 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8764 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8765 for (p = pStart; p < pEnd; ++p) { 8766 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8767 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8768 else numbers[p - pStart] += shift; 8769 } 8770 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8771 if (globalSize) { 8772 PetscLayout layout; 8773 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8774 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8775 PetscCall(PetscLayoutDestroy(&layout)); 8776 } 8777 PetscCall(PetscSectionDestroy(§ion)); 8778 PetscCall(PetscSectionDestroy(&globalSection)); 8779 PetscFunctionReturn(PETSC_SUCCESS); 8780 } 8781 8782 /*@ 8783 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8784 8785 Input Parameters: 8786 + dm - The `DMPLEX` object 8787 - includeAll - Whether to include all cells, or just the simplex and box cells 8788 8789 Output Parameter: 8790 . globalCellNumbers - Global cell numbers for all cells on this process 8791 8792 Level: developer 8793 8794 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8795 @*/ 8796 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8797 { 8798 PetscInt cellHeight, cStart, cEnd; 8799 8800 PetscFunctionBegin; 8801 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8802 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8803 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8804 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8805 PetscFunctionReturn(PETSC_SUCCESS); 8806 } 8807 8808 /*@ 8809 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8810 8811 Input Parameter: 8812 . dm - The `DMPLEX` object 8813 8814 Output Parameter: 8815 . globalCellNumbers - Global cell numbers for all cells on this process 8816 8817 Level: developer 8818 8819 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8820 @*/ 8821 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8822 { 8823 DM_Plex *mesh = (DM_Plex *)dm->data; 8824 8825 PetscFunctionBegin; 8826 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8827 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8828 *globalCellNumbers = mesh->globalCellNumbers; 8829 PetscFunctionReturn(PETSC_SUCCESS); 8830 } 8831 8832 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8833 { 8834 PetscInt vStart, vEnd; 8835 8836 PetscFunctionBegin; 8837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8838 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8839 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8840 PetscFunctionReturn(PETSC_SUCCESS); 8841 } 8842 8843 /*@ 8844 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8845 8846 Input Parameter: 8847 . dm - The `DMPLEX` object 8848 8849 Output Parameter: 8850 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8851 8852 Level: developer 8853 8854 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8855 @*/ 8856 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8857 { 8858 DM_Plex *mesh = (DM_Plex *)dm->data; 8859 8860 PetscFunctionBegin; 8861 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8862 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8863 *globalVertexNumbers = mesh->globalVertexNumbers; 8864 PetscFunctionReturn(PETSC_SUCCESS); 8865 } 8866 8867 /*@ 8868 DMPlexCreatePointNumbering - Create a global numbering for all points. 8869 8870 Collective 8871 8872 Input Parameter: 8873 . dm - The `DMPLEX` object 8874 8875 Output Parameter: 8876 . globalPointNumbers - Global numbers for all points on this process 8877 8878 Level: developer 8879 8880 Notes: 8881 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8882 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8883 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8884 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8885 8886 The partitioned mesh is 8887 ``` 8888 (2)--0--(3)--1--(4) (1)--0--(2) 8889 ``` 8890 and its global numbering is 8891 ``` 8892 (3)--0--(4)--1--(5)--2--(6) 8893 ``` 8894 Then the global numbering is provided as 8895 ``` 8896 [0] Number of indices in set 5 8897 [0] 0 0 8898 [0] 1 1 8899 [0] 2 3 8900 [0] 3 4 8901 [0] 4 -6 8902 [1] Number of indices in set 3 8903 [1] 0 2 8904 [1] 1 5 8905 [1] 2 6 8906 ``` 8907 8908 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8909 @*/ 8910 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8911 { 8912 IS nums[4]; 8913 PetscInt depths[4], gdepths[4], starts[4]; 8914 PetscInt depth, d, shift = 0; 8915 PetscBool empty = PETSC_FALSE; 8916 8917 PetscFunctionBegin; 8918 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8919 PetscCall(DMPlexGetDepth(dm, &depth)); 8920 // For unstratified meshes use dim instead of depth 8921 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8922 // If any stratum is empty, we must mark all empty 8923 for (d = 0; d <= depth; ++d) { 8924 PetscInt end; 8925 8926 depths[d] = depth - d; 8927 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8928 if (!(starts[d] - end)) empty = PETSC_TRUE; 8929 } 8930 if (empty) 8931 for (d = 0; d <= depth; ++d) { 8932 depths[d] = -1; 8933 starts[d] = -1; 8934 } 8935 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8936 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8937 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]); 8938 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8939 for (d = 0; d <= depth; ++d) { 8940 PetscInt pStart, pEnd, gsize; 8941 8942 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8943 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8944 shift += gsize; 8945 } 8946 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8947 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8948 PetscFunctionReturn(PETSC_SUCCESS); 8949 } 8950 8951 /*@ 8952 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8953 8954 Collective 8955 8956 Input Parameter: 8957 . dm - The `DMPLEX` object 8958 8959 Output Parameter: 8960 . globalEdgeNumbers - Global numbers for all edges on this process 8961 8962 Level: developer 8963 8964 Notes: 8965 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). 8966 8967 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8968 @*/ 8969 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8970 { 8971 PetscSF sf; 8972 PetscInt eStart, eEnd; 8973 8974 PetscFunctionBegin; 8975 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8976 PetscCall(DMGetPointSF(dm, &sf)); 8977 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8978 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8979 PetscFunctionReturn(PETSC_SUCCESS); 8980 } 8981 8982 /*@ 8983 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8984 8985 Input Parameter: 8986 . dm - The `DMPLEX` object 8987 8988 Output Parameter: 8989 . ranks - The rank field 8990 8991 Options Database Key: 8992 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8993 8994 Level: intermediate 8995 8996 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8997 @*/ 8998 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8999 { 9000 DM rdm; 9001 PetscFE fe; 9002 PetscScalar *r; 9003 PetscMPIInt rank; 9004 DMPolytopeType ct; 9005 PetscInt dim, cStart, cEnd, c; 9006 PetscBool simplex; 9007 9008 PetscFunctionBeginUser; 9009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9010 PetscAssertPointer(ranks, 2); 9011 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9012 PetscCall(DMClone(dm, &rdm)); 9013 PetscCall(DMGetDimension(rdm, &dim)); 9014 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9015 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9016 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9017 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9018 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9019 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9020 PetscCall(PetscFEDestroy(&fe)); 9021 PetscCall(DMCreateDS(rdm)); 9022 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9023 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9024 PetscCall(VecGetArray(*ranks, &r)); 9025 for (c = cStart; c < cEnd; ++c) { 9026 PetscScalar *lr; 9027 9028 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9029 if (lr) *lr = rank; 9030 } 9031 PetscCall(VecRestoreArray(*ranks, &r)); 9032 PetscCall(DMDestroy(&rdm)); 9033 PetscFunctionReturn(PETSC_SUCCESS); 9034 } 9035 9036 /*@ 9037 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9038 9039 Input Parameters: 9040 + dm - The `DMPLEX` 9041 - label - The `DMLabel` 9042 9043 Output Parameter: 9044 . val - The label value field 9045 9046 Options Database Key: 9047 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9048 9049 Level: intermediate 9050 9051 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9052 @*/ 9053 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9054 { 9055 DM rdm, plex; 9056 Vec lval; 9057 PetscSection section; 9058 PetscFE fe; 9059 PetscScalar *v; 9060 PetscInt dim, pStart, pEnd, p, cStart; 9061 DMPolytopeType ct; 9062 char name[PETSC_MAX_PATH_LEN]; 9063 const char *lname, *prefix; 9064 9065 PetscFunctionBeginUser; 9066 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9067 PetscAssertPointer(label, 2); 9068 PetscAssertPointer(val, 3); 9069 PetscCall(DMClone(dm, &rdm)); 9070 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9071 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9072 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9073 PetscCall(DMDestroy(&plex)); 9074 PetscCall(DMGetDimension(rdm, &dim)); 9075 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9076 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9077 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9078 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9079 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9080 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9081 PetscCall(PetscFEDestroy(&fe)); 9082 PetscCall(DMCreateDS(rdm)); 9083 PetscCall(DMCreateGlobalVector(rdm, val)); 9084 PetscCall(DMCreateLocalVector(rdm, &lval)); 9085 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9086 PetscCall(DMGetLocalSection(rdm, §ion)); 9087 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9088 PetscCall(VecGetArray(lval, &v)); 9089 for (p = pStart; p < pEnd; ++p) { 9090 PetscInt cval, dof, off; 9091 9092 PetscCall(PetscSectionGetDof(section, p, &dof)); 9093 if (!dof) continue; 9094 PetscCall(DMLabelGetValue(label, p, &cval)); 9095 PetscCall(PetscSectionGetOffset(section, p, &off)); 9096 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9097 } 9098 PetscCall(VecRestoreArray(lval, &v)); 9099 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9100 PetscCall(VecDestroy(&lval)); 9101 PetscCall(DMDestroy(&rdm)); 9102 PetscFunctionReturn(PETSC_SUCCESS); 9103 } 9104 9105 /*@ 9106 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9107 9108 Input Parameter: 9109 . dm - The `DMPLEX` object 9110 9111 Level: developer 9112 9113 Notes: 9114 This is a useful diagnostic when creating meshes programmatically. 9115 9116 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9117 9118 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9119 @*/ 9120 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9121 { 9122 PetscSection coneSection, supportSection; 9123 const PetscInt *cone, *support; 9124 PetscInt coneSize, c, supportSize, s; 9125 PetscInt pStart, pEnd, p, pp, csize, ssize; 9126 PetscBool storagecheck = PETSC_TRUE; 9127 9128 PetscFunctionBegin; 9129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9130 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9131 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9132 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9133 /* Check that point p is found in the support of its cone points, and vice versa */ 9134 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9135 for (p = pStart; p < pEnd; ++p) { 9136 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9137 PetscCall(DMPlexGetCone(dm, p, &cone)); 9138 for (c = 0; c < coneSize; ++c) { 9139 PetscBool dup = PETSC_FALSE; 9140 PetscInt d; 9141 for (d = c - 1; d >= 0; --d) { 9142 if (cone[c] == cone[d]) { 9143 dup = PETSC_TRUE; 9144 break; 9145 } 9146 } 9147 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9148 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9149 for (s = 0; s < supportSize; ++s) { 9150 if (support[s] == p) break; 9151 } 9152 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9153 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9154 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9155 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9156 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9157 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9158 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9159 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]); 9160 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9161 } 9162 } 9163 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9164 if (p != pp) { 9165 storagecheck = PETSC_FALSE; 9166 continue; 9167 } 9168 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9169 PetscCall(DMPlexGetSupport(dm, p, &support)); 9170 for (s = 0; s < supportSize; ++s) { 9171 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9172 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9173 for (c = 0; c < coneSize; ++c) { 9174 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9175 if (cone[c] != pp) { 9176 c = 0; 9177 break; 9178 } 9179 if (cone[c] == p) break; 9180 } 9181 if (c >= coneSize) { 9182 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9183 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9184 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9185 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9186 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9187 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9188 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9189 } 9190 } 9191 } 9192 if (storagecheck) { 9193 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9194 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9195 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9196 } 9197 PetscFunctionReturn(PETSC_SUCCESS); 9198 } 9199 9200 /* 9201 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. 9202 */ 9203 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9204 { 9205 DMPolytopeType cct; 9206 PetscInt ptpoints[4]; 9207 const PetscInt *cone, *ccone, *ptcone; 9208 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9209 9210 PetscFunctionBegin; 9211 *unsplit = 0; 9212 switch (ct) { 9213 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9214 ptpoints[npt++] = c; 9215 break; 9216 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9217 PetscCall(DMPlexGetCone(dm, c, &cone)); 9218 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9219 for (cp = 0; cp < coneSize; ++cp) { 9220 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9221 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9222 } 9223 break; 9224 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9225 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9226 PetscCall(DMPlexGetCone(dm, c, &cone)); 9227 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9228 for (cp = 0; cp < coneSize; ++cp) { 9229 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9230 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9231 for (ccp = 0; ccp < cconeSize; ++ccp) { 9232 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9233 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9234 PetscInt p; 9235 for (p = 0; p < npt; ++p) 9236 if (ptpoints[p] == ccone[ccp]) break; 9237 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9238 } 9239 } 9240 } 9241 break; 9242 default: 9243 break; 9244 } 9245 for (pt = 0; pt < npt; ++pt) { 9246 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9247 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9248 } 9249 PetscFunctionReturn(PETSC_SUCCESS); 9250 } 9251 9252 /*@ 9253 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9254 9255 Input Parameters: 9256 + dm - The `DMPLEX` object 9257 - cellHeight - Normally 0 9258 9259 Level: developer 9260 9261 Notes: 9262 This is a useful diagnostic when creating meshes programmatically. 9263 Currently applicable only to homogeneous simplex or tensor meshes. 9264 9265 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9266 9267 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9268 @*/ 9269 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9270 { 9271 DMPlexInterpolatedFlag interp; 9272 DMPolytopeType ct; 9273 PetscInt vStart, vEnd, cStart, cEnd, c; 9274 9275 PetscFunctionBegin; 9276 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9277 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9278 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9279 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9280 for (c = cStart; c < cEnd; ++c) { 9281 PetscInt *closure = NULL; 9282 PetscInt coneSize, closureSize, cl, Nv = 0; 9283 9284 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9285 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9286 if (interp == DMPLEX_INTERPOLATED_FULL) { 9287 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9288 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)); 9289 } 9290 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9291 for (cl = 0; cl < closureSize * 2; cl += 2) { 9292 const PetscInt p = closure[cl]; 9293 if ((p >= vStart) && (p < vEnd)) ++Nv; 9294 } 9295 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9296 /* Special Case: Tensor faces with identified vertices */ 9297 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9298 PetscInt unsplit; 9299 9300 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9301 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9302 } 9303 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)); 9304 } 9305 PetscFunctionReturn(PETSC_SUCCESS); 9306 } 9307 9308 /*@ 9309 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9310 9311 Collective 9312 9313 Input Parameters: 9314 + dm - The `DMPLEX` object 9315 - cellHeight - Normally 0 9316 9317 Level: developer 9318 9319 Notes: 9320 This is a useful diagnostic when creating meshes programmatically. 9321 This routine is only relevant for meshes that are fully interpolated across all ranks. 9322 It will error out if a partially interpolated mesh is given on some rank. 9323 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9324 9325 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9326 9327 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9328 @*/ 9329 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9330 { 9331 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9332 DMPlexInterpolatedFlag interpEnum; 9333 9334 PetscFunctionBegin; 9335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9336 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9337 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9338 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9339 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9340 PetscFunctionReturn(PETSC_SUCCESS); 9341 } 9342 9343 PetscCall(DMGetDimension(dm, &dim)); 9344 PetscCall(DMPlexGetDepth(dm, &depth)); 9345 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9346 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9347 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9348 for (c = cStart; c < cEnd; ++c) { 9349 const PetscInt *cone, *ornt, *faceSizes, *faces; 9350 const DMPolytopeType *faceTypes; 9351 DMPolytopeType ct; 9352 PetscInt numFaces, coneSize, f; 9353 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9354 9355 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9356 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9357 if (unsplit) continue; 9358 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9359 PetscCall(DMPlexGetCone(dm, c, &cone)); 9360 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9361 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9362 for (cl = 0; cl < closureSize * 2; cl += 2) { 9363 const PetscInt p = closure[cl]; 9364 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9365 } 9366 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9367 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); 9368 for (f = 0; f < numFaces; ++f) { 9369 DMPolytopeType fct; 9370 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9371 9372 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9373 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9374 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9375 const PetscInt p = fclosure[cl]; 9376 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9377 } 9378 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]); 9379 for (v = 0; v < fnumCorners; ++v) { 9380 if (fclosure[v] != faces[fOff + v]) { 9381 PetscInt v1; 9382 9383 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9384 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9385 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9386 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9387 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9388 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]); 9389 } 9390 } 9391 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9392 fOff += faceSizes[f]; 9393 } 9394 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9395 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9396 } 9397 } 9398 PetscFunctionReturn(PETSC_SUCCESS); 9399 } 9400 9401 /*@ 9402 DMPlexCheckGeometry - Check the geometry of mesh cells 9403 9404 Input Parameter: 9405 . dm - The `DMPLEX` object 9406 9407 Level: developer 9408 9409 Notes: 9410 This is a useful diagnostic when creating meshes programmatically. 9411 9412 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9413 9414 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9415 @*/ 9416 PetscErrorCode DMPlexCheckGeometry(DM dm) 9417 { 9418 Vec coordinates; 9419 PetscReal detJ, J[9], refVol = 1.0; 9420 PetscReal vol; 9421 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9422 9423 PetscFunctionBegin; 9424 PetscCall(DMGetDimension(dm, &dim)); 9425 PetscCall(DMGetCoordinateDim(dm, &dE)); 9426 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9427 PetscCall(DMPlexGetDepth(dm, &depth)); 9428 for (d = 0; d < dim; ++d) refVol *= 2.0; 9429 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9430 /* Make sure local coordinates are created, because that step is collective */ 9431 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9432 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9433 for (c = cStart; c < cEnd; ++c) { 9434 DMPolytopeType ct; 9435 PetscInt unsplit; 9436 PetscBool ignoreZeroVol = PETSC_FALSE; 9437 9438 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9439 switch (ct) { 9440 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9441 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9442 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9443 ignoreZeroVol = PETSC_TRUE; 9444 break; 9445 default: 9446 break; 9447 } 9448 switch (ct) { 9449 case DM_POLYTOPE_TRI_PRISM: 9450 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9451 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9452 case DM_POLYTOPE_PYRAMID: 9453 continue; 9454 default: 9455 break; 9456 } 9457 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9458 if (unsplit) continue; 9459 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9460 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); 9461 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9462 /* This should work with periodicity since DG coordinates should be used */ 9463 if (depth > 1) { 9464 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9465 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); 9466 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9467 } 9468 } 9469 PetscFunctionReturn(PETSC_SUCCESS); 9470 } 9471 9472 /*@ 9473 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9474 9475 Collective 9476 9477 Input Parameters: 9478 + dm - The `DMPLEX` object 9479 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9480 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9481 9482 Level: developer 9483 9484 Notes: 9485 This is mainly intended for debugging/testing purposes. 9486 9487 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9488 9489 Extra roots can come from periodic cuts, where additional points appear on the boundary 9490 9491 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9492 @*/ 9493 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9494 { 9495 PetscInt l, nleaves, nroots, overlap; 9496 const PetscInt *locals; 9497 const PetscSFNode *remotes; 9498 PetscBool distributed; 9499 MPI_Comm comm; 9500 PetscMPIInt rank; 9501 9502 PetscFunctionBegin; 9503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9504 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9505 else pointSF = dm->sf; 9506 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9507 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9508 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9509 { 9510 PetscMPIInt mpiFlag; 9511 9512 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9513 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9514 } 9515 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9516 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9517 if (!distributed) { 9518 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); 9519 PetscFunctionReturn(PETSC_SUCCESS); 9520 } 9521 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); 9522 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9523 9524 /* Check SF graph is compatible with DMPlex chart */ 9525 { 9526 PetscInt pStart, pEnd, maxLeaf; 9527 9528 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9529 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9530 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9531 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9532 } 9533 9534 /* Check Point SF has no local points referenced */ 9535 for (l = 0; l < nleaves; l++) { 9536 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); 9537 } 9538 9539 /* Check there are no cells in interface */ 9540 if (!overlap) { 9541 PetscInt cellHeight, cStart, cEnd; 9542 9543 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9544 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9545 for (l = 0; l < nleaves; ++l) { 9546 const PetscInt point = locals ? locals[l] : l; 9547 9548 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9549 } 9550 } 9551 9552 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9553 { 9554 const PetscInt *rootdegree; 9555 9556 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9557 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9558 for (l = 0; l < nleaves; ++l) { 9559 const PetscInt point = locals ? locals[l] : l; 9560 const PetscInt *cone; 9561 PetscInt coneSize, c, idx; 9562 9563 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9564 PetscCall(DMPlexGetCone(dm, point, &cone)); 9565 for (c = 0; c < coneSize; ++c) { 9566 if (!rootdegree[cone[c]]) { 9567 if (locals) { 9568 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9569 } else { 9570 idx = (cone[c] < nleaves) ? cone[c] : -1; 9571 } 9572 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9573 } 9574 } 9575 } 9576 } 9577 PetscFunctionReturn(PETSC_SUCCESS); 9578 } 9579 9580 /*@ 9581 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9582 9583 Collective 9584 9585 Input Parameter: 9586 . dm - The `DMPLEX` object 9587 9588 Level: developer 9589 9590 Notes: 9591 This is mainly intended for debugging/testing purposes. 9592 9593 Other cell types which are disconnected would be caught by the symmetry and face checks. 9594 9595 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9596 9597 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9598 @*/ 9599 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9600 { 9601 PetscInt pStart, pEnd, vStart, vEnd; 9602 9603 PetscFunctionBegin; 9604 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9605 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9606 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9607 for (PetscInt v = vStart; v < vEnd; ++v) { 9608 PetscInt suppSize; 9609 9610 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9611 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9612 } 9613 PetscFunctionReturn(PETSC_SUCCESS); 9614 } 9615 9616 /*@ 9617 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9618 9619 Input Parameter: 9620 . dm - The `DMPLEX` object 9621 9622 Level: developer 9623 9624 Notes: 9625 This is a useful diagnostic when creating meshes programmatically. 9626 9627 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9628 9629 Currently does not include `DMPlexCheckCellShape()`. 9630 9631 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9632 @*/ 9633 PetscErrorCode DMPlexCheck(DM dm) 9634 { 9635 PetscInt cellHeight; 9636 9637 PetscFunctionBegin; 9638 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9639 PetscCall(DMPlexCheckSymmetry(dm)); 9640 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9641 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9642 PetscCall(DMPlexCheckGeometry(dm)); 9643 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9644 PetscCall(DMPlexCheckInterfaceCones(dm)); 9645 PetscCall(DMPlexCheckOrphanVertices(dm)); 9646 PetscFunctionReturn(PETSC_SUCCESS); 9647 } 9648 9649 typedef struct cell_stats { 9650 PetscReal min, max, sum, squaresum; 9651 PetscInt count; 9652 } cell_stats_t; 9653 9654 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9655 { 9656 PetscInt i, N = *len; 9657 9658 for (i = 0; i < N; i++) { 9659 cell_stats_t *A = (cell_stats_t *)a; 9660 cell_stats_t *B = (cell_stats_t *)b; 9661 9662 B->min = PetscMin(A->min, B->min); 9663 B->max = PetscMax(A->max, B->max); 9664 B->sum += A->sum; 9665 B->squaresum += A->squaresum; 9666 B->count += A->count; 9667 } 9668 } 9669 9670 /*@ 9671 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9672 9673 Collective 9674 9675 Input Parameters: 9676 + dm - The `DMPLEX` object 9677 . output - If true, statistics will be displayed on `stdout` 9678 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9679 9680 Level: developer 9681 9682 Notes: 9683 This is mainly intended for debugging/testing purposes. 9684 9685 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9686 9687 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9688 @*/ 9689 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9690 { 9691 DM dmCoarse; 9692 cell_stats_t stats, globalStats; 9693 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9694 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9695 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9696 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9697 PetscMPIInt rank, size; 9698 9699 PetscFunctionBegin; 9700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9701 stats.min = PETSC_MAX_REAL; 9702 stats.max = PETSC_MIN_REAL; 9703 stats.sum = stats.squaresum = 0.; 9704 stats.count = 0; 9705 9706 PetscCallMPI(MPI_Comm_size(comm, &size)); 9707 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9708 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9709 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9710 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9711 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9712 for (c = cStart; c < cEnd; c++) { 9713 PetscInt i; 9714 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9715 9716 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9717 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9718 for (i = 0; i < PetscSqr(cdim); ++i) { 9719 frobJ += J[i] * J[i]; 9720 frobInvJ += invJ[i] * invJ[i]; 9721 } 9722 cond2 = frobJ * frobInvJ; 9723 cond = PetscSqrtReal(cond2); 9724 9725 stats.min = PetscMin(stats.min, cond); 9726 stats.max = PetscMax(stats.max, cond); 9727 stats.sum += cond; 9728 stats.squaresum += cond2; 9729 stats.count++; 9730 if (output && cond > limit) { 9731 PetscSection coordSection; 9732 Vec coordsLocal; 9733 PetscScalar *coords = NULL; 9734 PetscInt Nv, d, clSize, cl, *closure = NULL; 9735 9736 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9737 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9738 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9739 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9740 for (i = 0; i < Nv / cdim; ++i) { 9741 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9742 for (d = 0; d < cdim; ++d) { 9743 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9744 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9745 } 9746 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9747 } 9748 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9749 for (cl = 0; cl < clSize * 2; cl += 2) { 9750 const PetscInt edge = closure[cl]; 9751 9752 if ((edge >= eStart) && (edge < eEnd)) { 9753 PetscReal len; 9754 9755 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9756 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9757 } 9758 } 9759 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9760 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9761 } 9762 } 9763 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9764 9765 if (size > 1) { 9766 PetscMPIInt blockLengths[2] = {4, 1}; 9767 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9768 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9769 MPI_Op statReduce; 9770 9771 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9772 PetscCallMPI(MPI_Type_commit(&statType)); 9773 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9774 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9775 PetscCallMPI(MPI_Op_free(&statReduce)); 9776 PetscCallMPI(MPI_Type_free(&statType)); 9777 } else { 9778 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9779 } 9780 if (rank == 0) { 9781 count = globalStats.count; 9782 min = globalStats.min; 9783 max = globalStats.max; 9784 mean = globalStats.sum / globalStats.count; 9785 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9786 } 9787 9788 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)); 9789 PetscCall(PetscFree2(J, invJ)); 9790 9791 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9792 if (dmCoarse) { 9793 PetscBool isplex; 9794 9795 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9796 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9797 } 9798 PetscFunctionReturn(PETSC_SUCCESS); 9799 } 9800 9801 /*@ 9802 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9803 orthogonal quality below given tolerance. 9804 9805 Collective 9806 9807 Input Parameters: 9808 + dm - The `DMPLEX` object 9809 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9810 - atol - [0, 1] Absolute tolerance for tagging cells. 9811 9812 Output Parameters: 9813 + OrthQual - `Vec` containing orthogonal quality per cell 9814 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9815 9816 Options Database Keys: 9817 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9818 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9819 9820 Level: intermediate 9821 9822 Notes: 9823 Orthogonal quality is given by the following formula\: 9824 9825 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9826 9827 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 9828 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9829 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9830 calculating the cosine of the angle between these vectors. 9831 9832 Orthogonal quality ranges from 1 (best) to 0 (worst). 9833 9834 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9835 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9836 9837 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9838 9839 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9840 @*/ 9841 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9842 { 9843 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9844 PetscInt *idx; 9845 PetscScalar *oqVals; 9846 const PetscScalar *cellGeomArr, *faceGeomArr; 9847 PetscReal *ci, *fi, *Ai; 9848 MPI_Comm comm; 9849 Vec cellgeom, facegeom; 9850 DM dmFace, dmCell; 9851 IS glob; 9852 ISLocalToGlobalMapping ltog; 9853 PetscViewer vwr; 9854 9855 PetscFunctionBegin; 9856 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9857 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9858 PetscAssertPointer(OrthQual, 4); 9859 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9860 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9861 PetscCall(DMGetDimension(dm, &nc)); 9862 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9863 { 9864 DMPlexInterpolatedFlag interpFlag; 9865 9866 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9867 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9868 PetscMPIInt rank; 9869 9870 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9871 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9872 } 9873 } 9874 if (OrthQualLabel) { 9875 PetscAssertPointer(OrthQualLabel, 5); 9876 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9877 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9878 } else { 9879 *OrthQualLabel = NULL; 9880 } 9881 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9882 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9883 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9884 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9885 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9886 PetscCall(VecCreate(comm, OrthQual)); 9887 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9888 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9889 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9890 PetscCall(VecSetUp(*OrthQual)); 9891 PetscCall(ISDestroy(&glob)); 9892 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9893 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9894 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9895 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9896 PetscCall(VecGetDM(cellgeom, &dmCell)); 9897 PetscCall(VecGetDM(facegeom, &dmFace)); 9898 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9899 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9900 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9901 PetscInt cellarr[2], *adj = NULL; 9902 PetscScalar *cArr, *fArr; 9903 PetscReal minvalc = 1.0, minvalf = 1.0; 9904 PetscFVCellGeom *cg; 9905 9906 idx[cellIter] = cell - cStart; 9907 cellarr[0] = cell; 9908 /* Make indexing into cellGeom easier */ 9909 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9910 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9911 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9912 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9913 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9914 PetscInt i; 9915 const PetscInt neigh = adj[cellneigh]; 9916 PetscReal normci = 0, normfi = 0, normai = 0; 9917 PetscFVCellGeom *cgneigh; 9918 PetscFVFaceGeom *fg; 9919 9920 /* Don't count ourselves in the neighbor list */ 9921 if (neigh == cell) continue; 9922 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9923 cellarr[1] = neigh; 9924 { 9925 PetscInt numcovpts; 9926 const PetscInt *covpts; 9927 9928 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9929 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9930 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9931 } 9932 9933 /* Compute c_i, f_i and their norms */ 9934 for (i = 0; i < nc; i++) { 9935 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9936 fi[i] = fg->centroid[i] - cg->centroid[i]; 9937 Ai[i] = fg->normal[i]; 9938 normci += PetscPowReal(ci[i], 2); 9939 normfi += PetscPowReal(fi[i], 2); 9940 normai += PetscPowReal(Ai[i], 2); 9941 } 9942 normci = PetscSqrtReal(normci); 9943 normfi = PetscSqrtReal(normfi); 9944 normai = PetscSqrtReal(normai); 9945 9946 /* Normalize and compute for each face-cell-normal pair */ 9947 for (i = 0; i < nc; i++) { 9948 ci[i] = ci[i] / normci; 9949 fi[i] = fi[i] / normfi; 9950 Ai[i] = Ai[i] / normai; 9951 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9952 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9953 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9954 } 9955 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9956 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9957 } 9958 PetscCall(PetscFree(adj)); 9959 PetscCall(PetscFree2(cArr, fArr)); 9960 /* Defer to cell if they're equal */ 9961 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9962 if (OrthQualLabel) { 9963 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9964 } 9965 } 9966 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9967 PetscCall(VecAssemblyBegin(*OrthQual)); 9968 PetscCall(VecAssemblyEnd(*OrthQual)); 9969 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9970 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9971 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9972 if (OrthQualLabel) { 9973 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9974 } 9975 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9976 PetscCall(PetscViewerDestroy(&vwr)); 9977 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9978 PetscFunctionReturn(PETSC_SUCCESS); 9979 } 9980 9981 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9982 * interpolator construction */ 9983 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9984 { 9985 PetscSection section, newSection, gsection; 9986 PetscSF sf; 9987 PetscBool hasConstraints, ghasConstraints; 9988 9989 PetscFunctionBegin; 9990 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9991 PetscAssertPointer(odm, 2); 9992 PetscCall(DMGetLocalSection(dm, §ion)); 9993 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9994 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9995 if (!ghasConstraints) { 9996 PetscCall(PetscObjectReference((PetscObject)dm)); 9997 *odm = dm; 9998 PetscFunctionReturn(PETSC_SUCCESS); 9999 } 10000 PetscCall(DMClone(dm, odm)); 10001 PetscCall(DMCopyFields(dm, *odm)); 10002 PetscCall(DMGetLocalSection(*odm, &newSection)); 10003 PetscCall(DMGetPointSF(*odm, &sf)); 10004 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10005 PetscCall(DMSetGlobalSection(*odm, gsection)); 10006 PetscCall(PetscSectionDestroy(&gsection)); 10007 PetscFunctionReturn(PETSC_SUCCESS); 10008 } 10009 10010 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10011 { 10012 DM dmco, dmfo; 10013 Mat interpo; 10014 Vec rscale; 10015 Vec cglobalo, clocal; 10016 Vec fglobal, fglobalo, flocal; 10017 PetscBool regular; 10018 10019 PetscFunctionBegin; 10020 PetscCall(DMGetFullDM(dmc, &dmco)); 10021 PetscCall(DMGetFullDM(dmf, &dmfo)); 10022 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10023 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10024 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10025 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10026 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10027 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10028 PetscCall(VecSet(cglobalo, 0.)); 10029 PetscCall(VecSet(clocal, 0.)); 10030 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10031 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10032 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10033 PetscCall(VecSet(fglobal, 0.)); 10034 PetscCall(VecSet(fglobalo, 0.)); 10035 PetscCall(VecSet(flocal, 0.)); 10036 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10037 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10038 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10039 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10040 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10041 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10042 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10043 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10044 *shift = fglobal; 10045 PetscCall(VecDestroy(&flocal)); 10046 PetscCall(VecDestroy(&fglobalo)); 10047 PetscCall(VecDestroy(&clocal)); 10048 PetscCall(VecDestroy(&cglobalo)); 10049 PetscCall(VecDestroy(&rscale)); 10050 PetscCall(MatDestroy(&interpo)); 10051 PetscCall(DMDestroy(&dmfo)); 10052 PetscCall(DMDestroy(&dmco)); 10053 PetscFunctionReturn(PETSC_SUCCESS); 10054 } 10055 10056 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10057 { 10058 PetscObject shifto; 10059 Vec shift; 10060 10061 PetscFunctionBegin; 10062 if (!interp) { 10063 Vec rscale; 10064 10065 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10066 PetscCall(VecDestroy(&rscale)); 10067 } else { 10068 PetscCall(PetscObjectReference((PetscObject)interp)); 10069 } 10070 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10071 if (!shifto) { 10072 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10073 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10074 shifto = (PetscObject)shift; 10075 PetscCall(VecDestroy(&shift)); 10076 } 10077 shift = (Vec)shifto; 10078 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10079 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10080 PetscCall(MatDestroy(&interp)); 10081 PetscFunctionReturn(PETSC_SUCCESS); 10082 } 10083 10084 /* Pointwise interpolation 10085 Just code FEM for now 10086 u^f = I u^c 10087 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10088 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10089 I_{ij} = psi^f_i phi^c_j 10090 */ 10091 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10092 { 10093 PetscSection gsc, gsf; 10094 PetscInt m, n; 10095 void *ctx; 10096 DM cdm; 10097 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10098 10099 PetscFunctionBegin; 10100 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10101 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10102 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10103 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10104 10105 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10106 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10107 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10108 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10109 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10110 10111 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10112 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10113 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10114 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10115 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10116 if (scaling) { 10117 /* Use naive scaling */ 10118 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10119 } 10120 PetscFunctionReturn(PETSC_SUCCESS); 10121 } 10122 10123 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10124 { 10125 VecScatter ctx; 10126 10127 PetscFunctionBegin; 10128 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10129 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10130 PetscCall(VecScatterDestroy(&ctx)); 10131 PetscFunctionReturn(PETSC_SUCCESS); 10132 } 10133 10134 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[]) 10135 { 10136 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10137 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10138 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10139 } 10140 10141 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10142 { 10143 DM dmc; 10144 PetscDS ds; 10145 Vec ones, locmass; 10146 IS cellIS; 10147 PetscFormKey key; 10148 PetscInt depth; 10149 10150 PetscFunctionBegin; 10151 PetscCall(DMClone(dm, &dmc)); 10152 PetscCall(DMCopyDisc(dm, dmc)); 10153 PetscCall(DMGetDS(dmc, &ds)); 10154 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10155 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10156 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10157 else PetscCall(DMGetLocalVector(dm, &locmass)); 10158 PetscCall(DMGetLocalVector(dm, &ones)); 10159 PetscCall(DMPlexGetDepth(dm, &depth)); 10160 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10161 PetscCall(VecSet(locmass, 0.0)); 10162 PetscCall(VecSet(ones, 1.0)); 10163 key.label = NULL; 10164 key.value = 0; 10165 key.field = 0; 10166 key.part = 0; 10167 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10168 PetscCall(ISDestroy(&cellIS)); 10169 if (mass) { 10170 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10171 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10172 } 10173 PetscCall(DMRestoreLocalVector(dm, &ones)); 10174 if (lmass) *lmass = locmass; 10175 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10176 PetscCall(DMDestroy(&dmc)); 10177 PetscFunctionReturn(PETSC_SUCCESS); 10178 } 10179 10180 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10181 { 10182 PetscSection gsc, gsf; 10183 PetscInt m, n; 10184 void *ctx; 10185 DM cdm; 10186 PetscBool regular; 10187 10188 PetscFunctionBegin; 10189 if (dmFine == dmCoarse) { 10190 DM dmc; 10191 PetscDS ds; 10192 PetscWeakForm wf; 10193 Vec u; 10194 IS cellIS; 10195 PetscFormKey key; 10196 PetscInt depth; 10197 10198 PetscCall(DMClone(dmFine, &dmc)); 10199 PetscCall(DMCopyDisc(dmFine, dmc)); 10200 PetscCall(DMGetDS(dmc, &ds)); 10201 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10202 PetscCall(PetscWeakFormClear(wf)); 10203 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10204 PetscCall(DMCreateMatrix(dmc, mass)); 10205 PetscCall(DMGetLocalVector(dmc, &u)); 10206 PetscCall(DMPlexGetDepth(dmc, &depth)); 10207 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10208 PetscCall(MatZeroEntries(*mass)); 10209 key.label = NULL; 10210 key.value = 0; 10211 key.field = 0; 10212 key.part = 0; 10213 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10214 PetscCall(ISDestroy(&cellIS)); 10215 PetscCall(DMRestoreLocalVector(dmc, &u)); 10216 PetscCall(DMDestroy(&dmc)); 10217 } else { 10218 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10219 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10220 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10221 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10222 10223 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10224 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10225 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10226 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10227 10228 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10229 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10230 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10231 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10232 } 10233 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10234 PetscFunctionReturn(PETSC_SUCCESS); 10235 } 10236 10237 /*@ 10238 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10239 10240 Input Parameter: 10241 . dm - The `DMPLEX` object 10242 10243 Output Parameter: 10244 . regular - The flag 10245 10246 Level: intermediate 10247 10248 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10249 @*/ 10250 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10251 { 10252 PetscFunctionBegin; 10253 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10254 PetscAssertPointer(regular, 2); 10255 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10256 PetscFunctionReturn(PETSC_SUCCESS); 10257 } 10258 10259 /*@ 10260 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10261 10262 Input Parameters: 10263 + dm - The `DMPLEX` object 10264 - regular - The flag 10265 10266 Level: intermediate 10267 10268 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10269 @*/ 10270 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10271 { 10272 PetscFunctionBegin; 10273 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10274 ((DM_Plex *)dm->data)->regularRefinement = regular; 10275 PetscFunctionReturn(PETSC_SUCCESS); 10276 } 10277 10278 /*@ 10279 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10280 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10281 10282 Not Collective 10283 10284 Input Parameter: 10285 . dm - The `DMPLEX` object 10286 10287 Output Parameters: 10288 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10289 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10290 10291 Level: intermediate 10292 10293 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10294 @*/ 10295 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10296 { 10297 DM_Plex *plex = (DM_Plex *)dm->data; 10298 10299 PetscFunctionBegin; 10300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10301 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10302 if (anchorSection) *anchorSection = plex->anchorSection; 10303 if (anchorIS) *anchorIS = plex->anchorIS; 10304 PetscFunctionReturn(PETSC_SUCCESS); 10305 } 10306 10307 /*@ 10308 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10309 10310 Collective 10311 10312 Input Parameters: 10313 + dm - The `DMPLEX` object 10314 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10315 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10316 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10317 10318 Level: intermediate 10319 10320 Notes: 10321 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10322 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10323 combination of other points' degrees of freedom. 10324 10325 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10326 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10327 10328 The reference counts of `anchorSection` and `anchorIS` are incremented. 10329 10330 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10331 @*/ 10332 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10333 { 10334 DM_Plex *plex = (DM_Plex *)dm->data; 10335 PetscMPIInt result; 10336 10337 PetscFunctionBegin; 10338 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10339 if (anchorSection) { 10340 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10341 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10342 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10343 } 10344 if (anchorIS) { 10345 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10346 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10347 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10348 } 10349 10350 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10351 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10352 plex->anchorSection = anchorSection; 10353 10354 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10355 PetscCall(ISDestroy(&plex->anchorIS)); 10356 plex->anchorIS = anchorIS; 10357 10358 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10359 PetscInt size, a, pStart, pEnd; 10360 const PetscInt *anchors; 10361 10362 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10363 PetscCall(ISGetLocalSize(anchorIS, &size)); 10364 PetscCall(ISGetIndices(anchorIS, &anchors)); 10365 for (a = 0; a < size; a++) { 10366 PetscInt p; 10367 10368 p = anchors[a]; 10369 if (p >= pStart && p < pEnd) { 10370 PetscInt dof; 10371 10372 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10373 if (dof) { 10374 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10375 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10376 } 10377 } 10378 } 10379 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10380 } 10381 /* reset the generic constraints */ 10382 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10383 PetscFunctionReturn(PETSC_SUCCESS); 10384 } 10385 10386 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10387 { 10388 PetscSection anchorSection; 10389 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10390 10391 PetscFunctionBegin; 10392 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10393 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10394 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10395 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10396 if (numFields) { 10397 PetscInt f; 10398 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10399 10400 for (f = 0; f < numFields; f++) { 10401 PetscInt numComp; 10402 10403 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10404 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10405 } 10406 } 10407 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10408 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10409 pStart = PetscMax(pStart, sStart); 10410 pEnd = PetscMin(pEnd, sEnd); 10411 pEnd = PetscMax(pStart, pEnd); 10412 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10413 for (p = pStart; p < pEnd; p++) { 10414 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10415 if (dof) { 10416 PetscCall(PetscSectionGetDof(section, p, &dof)); 10417 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10418 for (f = 0; f < numFields; f++) { 10419 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10420 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10421 } 10422 } 10423 } 10424 PetscCall(PetscSectionSetUp(*cSec)); 10425 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10426 PetscFunctionReturn(PETSC_SUCCESS); 10427 } 10428 10429 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10430 { 10431 PetscSection aSec; 10432 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10433 const PetscInt *anchors; 10434 PetscInt numFields, f; 10435 IS aIS; 10436 MatType mtype; 10437 PetscBool iscuda, iskokkos; 10438 10439 PetscFunctionBegin; 10440 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10441 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10442 PetscCall(PetscSectionGetStorageSize(section, &n)); 10443 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10444 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10445 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10446 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10447 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10448 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10449 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10450 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10451 else mtype = MATSEQAIJ; 10452 PetscCall(MatSetType(*cMat, mtype)); 10453 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10454 PetscCall(ISGetIndices(aIS, &anchors)); 10455 /* cSec will be a subset of aSec and section */ 10456 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10457 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10458 PetscCall(PetscMalloc1(m + 1, &i)); 10459 i[0] = 0; 10460 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10461 for (p = pStart; p < pEnd; p++) { 10462 PetscInt rDof, rOff, r; 10463 10464 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10465 if (!rDof) continue; 10466 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10467 if (numFields) { 10468 for (f = 0; f < numFields; f++) { 10469 annz = 0; 10470 for (r = 0; r < rDof; r++) { 10471 a = anchors[rOff + r]; 10472 if (a < sStart || a >= sEnd) continue; 10473 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10474 annz += aDof; 10475 } 10476 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10477 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10478 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10479 } 10480 } else { 10481 annz = 0; 10482 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10483 for (q = 0; q < dof; q++) { 10484 a = anchors[rOff + q]; 10485 if (a < sStart || a >= sEnd) continue; 10486 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10487 annz += aDof; 10488 } 10489 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10490 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10491 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10492 } 10493 } 10494 nnz = i[m]; 10495 PetscCall(PetscMalloc1(nnz, &j)); 10496 offset = 0; 10497 for (p = pStart; p < pEnd; p++) { 10498 if (numFields) { 10499 for (f = 0; f < numFields; f++) { 10500 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10501 for (q = 0; q < dof; q++) { 10502 PetscInt rDof, rOff, r; 10503 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10504 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10505 for (r = 0; r < rDof; r++) { 10506 PetscInt s; 10507 10508 a = anchors[rOff + r]; 10509 if (a < sStart || a >= sEnd) continue; 10510 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10511 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10512 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10513 } 10514 } 10515 } 10516 } else { 10517 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10518 for (q = 0; q < dof; q++) { 10519 PetscInt rDof, rOff, r; 10520 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10521 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10522 for (r = 0; r < rDof; r++) { 10523 PetscInt s; 10524 10525 a = anchors[rOff + r]; 10526 if (a < sStart || a >= sEnd) continue; 10527 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10528 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10529 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10530 } 10531 } 10532 } 10533 } 10534 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10535 PetscCall(PetscFree(i)); 10536 PetscCall(PetscFree(j)); 10537 PetscCall(ISRestoreIndices(aIS, &anchors)); 10538 PetscFunctionReturn(PETSC_SUCCESS); 10539 } 10540 10541 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10542 { 10543 DM_Plex *plex = (DM_Plex *)dm->data; 10544 PetscSection anchorSection, section, cSec; 10545 Mat cMat; 10546 10547 PetscFunctionBegin; 10548 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10549 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10550 if (anchorSection) { 10551 PetscInt Nf; 10552 10553 PetscCall(DMGetLocalSection(dm, §ion)); 10554 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10555 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10556 PetscCall(DMGetNumFields(dm, &Nf)); 10557 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10558 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10559 PetscCall(PetscSectionDestroy(&cSec)); 10560 PetscCall(MatDestroy(&cMat)); 10561 } 10562 PetscFunctionReturn(PETSC_SUCCESS); 10563 } 10564 10565 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10566 { 10567 IS subis; 10568 PetscSection section, subsection; 10569 10570 PetscFunctionBegin; 10571 PetscCall(DMGetLocalSection(dm, §ion)); 10572 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10573 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10574 /* Create subdomain */ 10575 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10576 /* Create submodel */ 10577 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10578 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10579 PetscCall(DMSetLocalSection(*subdm, subsection)); 10580 PetscCall(PetscSectionDestroy(&subsection)); 10581 PetscCall(DMCopyDisc(dm, *subdm)); 10582 /* Create map from submodel to global model */ 10583 if (is) { 10584 PetscSection sectionGlobal, subsectionGlobal; 10585 IS spIS; 10586 const PetscInt *spmap; 10587 PetscInt *subIndices; 10588 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10589 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10590 10591 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10592 PetscCall(ISGetIndices(spIS, &spmap)); 10593 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10594 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10595 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10596 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10597 for (p = pStart; p < pEnd; ++p) { 10598 PetscInt gdof, pSubSize = 0; 10599 10600 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10601 if (gdof > 0) { 10602 for (f = 0; f < Nf; ++f) { 10603 PetscInt fdof, fcdof; 10604 10605 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10606 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10607 pSubSize += fdof - fcdof; 10608 } 10609 subSize += pSubSize; 10610 if (pSubSize) { 10611 if (bs < 0) { 10612 bs = pSubSize; 10613 } else if (bs != pSubSize) { 10614 /* Layout does not admit a pointwise block size */ 10615 bs = 1; 10616 } 10617 } 10618 } 10619 } 10620 /* Must have same blocksize on all procs (some might have no points) */ 10621 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10622 bsLocal[1] = bs; 10623 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10624 if (bsMinMax[0] != bsMinMax[1]) { 10625 bs = 1; 10626 } else { 10627 bs = bsMinMax[0]; 10628 } 10629 PetscCall(PetscMalloc1(subSize, &subIndices)); 10630 for (p = pStart; p < pEnd; ++p) { 10631 PetscInt gdof, goff; 10632 10633 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10634 if (gdof > 0) { 10635 const PetscInt point = spmap[p]; 10636 10637 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10638 for (f = 0; f < Nf; ++f) { 10639 PetscInt fdof, fcdof, fc, f2, poff = 0; 10640 10641 /* Can get rid of this loop by storing field information in the global section */ 10642 for (f2 = 0; f2 < f; ++f2) { 10643 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10644 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10645 poff += fdof - fcdof; 10646 } 10647 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10648 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10649 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10650 } 10651 } 10652 } 10653 PetscCall(ISRestoreIndices(spIS, &spmap)); 10654 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10655 if (bs > 1) { 10656 /* We need to check that the block size does not come from non-contiguous fields */ 10657 PetscInt i, j, set = 1; 10658 for (i = 0; i < subSize; i += bs) { 10659 for (j = 0; j < bs; ++j) { 10660 if (subIndices[i + j] != subIndices[i] + j) { 10661 set = 0; 10662 break; 10663 } 10664 } 10665 } 10666 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10667 } 10668 /* Attach nullspace */ 10669 for (f = 0; f < Nf; ++f) { 10670 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10671 if ((*subdm)->nullspaceConstructors[f]) break; 10672 } 10673 if (f < Nf) { 10674 MatNullSpace nullSpace; 10675 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10676 10677 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10678 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10679 } 10680 } 10681 PetscFunctionReturn(PETSC_SUCCESS); 10682 } 10683 10684 /*@ 10685 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10686 10687 Input Parameters: 10688 + dm - The `DM` 10689 - dummy - unused argument 10690 10691 Options Database Key: 10692 . -dm_plex_monitor_throughput - Activate the monitor 10693 10694 Level: developer 10695 10696 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10697 @*/ 10698 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10699 { 10700 PetscLogHandler default_handler; 10701 10702 PetscFunctionBegin; 10703 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10704 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10705 if (default_handler) { 10706 PetscLogEvent event; 10707 PetscEventPerfInfo eventInfo; 10708 PetscReal cellRate, flopRate; 10709 PetscInt cStart, cEnd, Nf, N; 10710 const char *name; 10711 10712 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10713 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10714 PetscCall(DMGetNumFields(dm, &Nf)); 10715 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10716 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10717 N = (cEnd - cStart) * Nf * eventInfo.count; 10718 flopRate = eventInfo.flops / eventInfo.time; 10719 cellRate = N / eventInfo.time; 10720 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))); 10721 } else { 10722 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."); 10723 } 10724 PetscFunctionReturn(PETSC_SUCCESS); 10725 } 10726